Add sources for API 35

Downloaded from https://dl.google.com/android/repository/source-35_r01.zip
using SdkManager in Studio

Test: None
Change-Id: I83f78aa820b66edfdc9f8594d17bc7b6cacccec1
diff --git a/android-35/java/util/AbstractCollection.java b/android-35/java/util/AbstractCollection.java
new file mode 100644
index 0000000..4912ac5
--- /dev/null
+++ b/android-35/java/util/AbstractCollection.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * This class provides a skeletal implementation of the {@code Collection}
+ * interface, to minimize the effort required to implement this interface. <p>
+ *
+ * To implement an unmodifiable collection, the programmer needs only to
+ * extend this class and provide implementations for the {@code iterator} and
+ * {@code size} methods.  (The iterator returned by the {@code iterator}
+ * method must implement {@code hasNext} and {@code next}.)<p>
+ *
+ * To implement a modifiable collection, the programmer must additionally
+ * override this class's {@code add} method (which otherwise throws an
+ * {@code UnsupportedOperationException}), and the iterator returned by the
+ * {@code iterator} method must additionally implement its {@code remove}
+ * method.<p>
+ *
+ * The programmer should generally provide a void (no argument) and
+ * {@code Collection} constructor, as per the recommendation in the
+ * {@code Collection} interface specification.<p>
+ *
+ * The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if
+ * the collection being implemented admits a more efficient implementation.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractCollection<E> implements Collection<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractCollection() {
+    }
+
+    // Query Operations
+
+    /**
+     * Returns an iterator over the elements contained in this collection.
+     *
+     * @return an iterator over the elements contained in this collection
+     */
+    public abstract Iterator<E> iterator();
+
+    public abstract int size();
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code size() == 0}.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the elements in the collection,
+     * checking each element in turn for equality with the specified element.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean contains(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return true;
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns an array containing all the elements
+     * returned by this collection's iterator, in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * The length of the returned array is equal to the number of elements
+     * returned by the iterator, even if the size of this collection changes
+     * during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray();
+     * }</pre>
+     */
+    public Object[] toArray() {
+        // Estimate size of array; be prepared to see more or fewer elements
+        Object[] r = new Object[size()];
+        Iterator<E> it = iterator();
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) // fewer elements than expected
+                return Arrays.copyOf(r, i);
+            r[i] = it.next();
+        }
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns an array containing all the elements
+     * returned by this collection's iterator in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * If the number of elements returned by the iterator is too large to
+     * fit into the specified array, then the elements are returned in a
+     * newly allocated array with length equal to the number of elements
+     * returned by the iterator, even if the size of this collection
+     * changes during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray(a);
+     * }</pre>
+     *
+     * @throws ArrayStoreException  {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        // Estimate size of array; be prepared to see more or fewer elements
+        int size = size();
+        T[] r = a.length >= size ? a :
+                  (T[])java.lang.reflect.Array
+                  .newInstance(a.getClass().getComponentType(), size);
+        Iterator<E> it = iterator();
+
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) { // fewer elements than expected
+                if (a == r) {
+                    r[i] = null; // null-terminate
+                } else if (a.length < i) {
+                    return Arrays.copyOf(r, i);
+                } else {
+                    System.arraycopy(r, 0, a, 0, i);
+                    if (a.length > i) {
+                        a[i] = null;
+                    }
+                }
+                return a;
+            }
+            r[i] = (T)it.next();
+        }
+        // more elements than expected
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * Reallocates the array being used within toArray when the iterator
+     * returned more elements than expected, and finishes filling it from
+     * the iterator.
+     *
+     * @param r the array, replete with previously stored elements
+     * @param it the in-progress iterator over this collection
+     * @return array containing the elements in the given array, plus any
+     *         further elements returned by the iterator, trimmed to size
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
+        int len = r.length;
+        int i = len;
+        while (it.hasNext()) {
+            if (i == len) {
+                len = ArraysSupport.newLength(len,
+                        1,             /* minimum growth */
+                        (len >> 1) + 1 /* preferred growth */);
+                r = Arrays.copyOf(r, len);
+            }
+            r[i++] = (T)it.next();
+        }
+        // trim if overallocated
+        return (i == len) ? r : Arrays.copyOf(r, i);
+    }
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     */
+    public boolean add(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the collection looking for the
+     * specified element.  If it finds the element, it removes the element
+     * from the collection using the iterator's remove method.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} if the iterator returned by this
+     * collection's iterator method does not implement the {@code remove}
+     * method and this collection contains the specified object.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public boolean remove(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext()) {
+                if (it.next()==null) {
+                    it.remove();
+                    return true;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                if (o.equals(it.next())) {
+                    it.remove();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the specified collection,
+     * checking each element returned by the iterator in turn to see
+     * if it's contained in this collection.  If all elements are so
+     * contained {@code true} is returned, otherwise {@code false}.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        for (Object e : c)
+            if (!contains(e))
+                return false;
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the specified collection, and adds
+     * each object returned by the iterator to this collection, in turn.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} unless {@code add} is
+     * overridden (assuming the specified collection is non-empty).
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     *
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's so contained, it's removed from
+     * this collection with the iterator's {@code remove} method.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the iterator returned by the
+     * {@code iterator} method does not implement the {@code remove} method
+     * and this collection contains one or more elements in common with the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<?> it = iterator();
+        while (it.hasNext()) {
+            if (c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's not so contained, it's removed
+     * from this collection with the iterator's {@code remove} method.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the iterator returned by the
+     * {@code iterator} method does not implement the {@code remove} method
+     * and this collection contains one or more elements not present in the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            if (!c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over this collection, removing each
+     * element using the {@code Iterator.remove} operation.  Most
+     * implementations will probably choose to override this method for
+     * efficiency.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the iterator returned by this
+     * collection's {@code iterator} method does not implement the
+     * {@code remove} method and this collection is non-empty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            it.next();
+            it.remove();
+        }
+    }
+
+
+    //  String conversion
+
+    /**
+     * Returns a string representation of this collection.  The string
+     * representation consists of a list of the collection's elements in the
+     * order they are returned by its iterator, enclosed in square brackets
+     * ({@code "[]"}).  Adjacent elements are separated by the characters
+     * {@code ", "} (comma and space).  Elements are converted to strings as
+     * by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this collection
+     */
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/android-35/java/util/AbstractList.java b/android-35/java/util/AbstractList.java
new file mode 100644
index 0000000..64dd471
--- /dev/null
+++ b/android-35/java/util/AbstractList.java
@@ -0,0 +1,944 @@
+/*
+ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * This class provides a skeletal implementation of the {@link List}
+ * interface to minimize the effort required to implement this interface
+ * backed by a "random access" data store (such as an array).  For sequential
+ * access data (such as a linked list), {@link AbstractSequentialList} should
+ * be used in preference to this class.
+ *
+ * <p>To implement an unmodifiable list, the programmer needs only to extend
+ * this class and provide implementations for the {@link #get(int)} and
+ * {@link List#size() size()} methods.
+ *
+ * <p>To implement a modifiable list, the programmer must additionally
+ * override the {@link #set(int, Object) set(int, E)} method (which otherwise
+ * throws an {@code UnsupportedOperationException}).  If the list is
+ * variable-size the programmer must additionally override the
+ * {@link #add(int, Object) add(int, E)} and {@link #remove(int)} methods.
+ *
+ * <p>The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the {@link Collection} interface
+ * specification.
+ *
+ * <p>Unlike the other abstract collection implementations, the programmer does
+ * <i>not</i> have to provide an iterator implementation; the iterator and
+ * list iterator are implemented by this class, on top of the "random access"
+ * methods:
+ * {@link #get(int)},
+ * {@link #set(int, Object) set(int, E)},
+ * {@link #add(int, Object) add(int, E)} and
+ * {@link #remove(int)}.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * collection being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @since 1.2
+ */
+
+public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractList() {
+    }
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @implSpec
+     * This implementation calls {@code add(size(), e)}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    public boolean add(E e) {
+        add(size(), e);
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract E get(int index);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+
+    // Search Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator (with
+     * {@code listIterator()}).  Then, it iterates over the list until the
+     * specified element is found or the end of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        ListIterator<E> it = listIterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return it.previousIndex();
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return it.previousIndex();
+        }
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator that points to the end
+     * of the list (with {@code listIterator(size())}).  Then, it iterates
+     * backwards over the list until the specified element is found, or the
+     * beginning of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        ListIterator<E> it = listIterator(size());
+        if (o==null) {
+            while (it.hasPrevious())
+                if (it.previous()==null)
+                    return it.nextIndex();
+        } else {
+            while (it.hasPrevious())
+                if (o.equals(it.previous()))
+                    return it.nextIndex();
+        }
+        return -1;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @implSpec
+     * This implementation calls {@code removeRange(0, size())}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless {@code remove(int
+     * index)} or {@code removeRange(int fromIndex, int toIndex)} is
+     * overridden.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    public void clear() {
+        removeRange(0, size());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation gets an iterator over the specified collection
+     * and iterates over it, inserting the elements obtained from the
+     * iterator into this list at the appropriate position, one at a time,
+     * using {@code add(int, E)}.
+     * Many implementations will override this method for efficiency.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        rangeCheckForAdd(index);
+        boolean modified = false;
+        for (E e : c) {
+            add(index++, e);
+            modified = true;
+        }
+        return modified;
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * iterator interface, relying on the backing list's {@code size()},
+     * {@code get(int)}, and {@code remove(int)} methods.
+     *
+     * <p>Note that the iterator returned by this method will throw an
+     * {@link UnsupportedOperationException} in response to its
+     * {@code remove} method unless the list's {@code remove(int)} method is
+     * overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification
+     * for the (protected) {@link #modCount} field.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code listIterator(0)}.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return listIterator(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * {@code ListIterator} interface that extends the implementation of the
+     * {@code Iterator} interface returned by the {@code iterator()} method.
+     * The {@code ListIterator} implementation relies on the backing list's
+     * {@code get(int)}, {@code set(int, E)}, {@code add(int, E)}
+     * and {@code remove(int)} methods.
+     *
+     * <p>Note that the list iterator returned by this implementation will
+     * throw an {@link UnsupportedOperationException} in response to its
+     * {@code remove}, {@code set} and {@code add} methods unless the
+     * list's {@code remove(int)}, {@code set(int, E)}, and
+     * {@code add(int, E)} methods are overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification for
+     * the (protected) {@link #modCount} field.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(final int index) {
+        rangeCheckForAdd(index);
+
+        return new ListItr(index);
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Index of element to be returned by subsequent call to next.
+         */
+        int cursor = 0;
+
+        /**
+         * Index of element returned by most recent call to next or
+         * previous.  Reset to -1 if this element is deleted by a call
+         * to remove.
+         */
+        int lastRet = -1;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * List should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor != size();
+        }
+
+        public E next() {
+            checkForComodification();
+            try {
+                int i = cursor;
+                E next = get(i);
+                lastRet = i;
+                cursor = i + 1;
+                return next;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException(e);
+            }
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.remove(lastRet);
+                if (lastRet < cursor)
+                    cursor--;
+                lastRet = -1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException e) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            try {
+                int i = cursor - 1;
+                E previous = get(i);
+                lastRet = cursor = i;
+                return previous;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException(e);
+            }
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor-1;
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.set(lastRet, e);
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            checkForComodification();
+
+            try {
+                int i = cursor;
+                AbstractList.this.add(i, e);
+                lastRet = -1;
+                cursor = i + 1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a list that subclasses
+     * {@code AbstractList}.  The subclass stores, in private fields, the
+     * size of the subList (which can change over its lifetime), and the
+     * expected {@code modCount} value of the backing list.  There are two
+     * variants of the subclass, one of which implements {@code RandomAccess}.
+     * If this list implements {@code RandomAccess} the returned list will
+     * be an instance of the subclass that implements {@code RandomAccess}.
+     *
+     * <p>The subclass's {@code set(int, E)}, {@code get(int)},
+     * {@code add(int, E)}, {@code remove(int)}, {@code addAll(int,
+     * Collection)} and {@code removeRange(int, int)} methods all
+     * delegate to the corresponding methods on the backing abstract list,
+     * after bounds-checking the index and adjusting for the offset.  The
+     * {@code addAll(Collection c)} method merely returns {@code addAll(size,
+     * c)}.
+     *
+     * <p>The {@code listIterator(int)} method returns a "wrapper object"
+     * over a list iterator on the backing list, which is created with the
+     * corresponding method on the backing list.  The {@code iterator} method
+     * merely returns {@code listIterator()}, and the {@code size} method
+     * merely returns the subclass's {@code size} field.
+     *
+     * <p>All methods first check to see if the actual {@code modCount} of
+     * the backing list is equal to its expected value, and throw a
+     * {@code ConcurrentModificationException} if it is not.
+     *
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size());
+        return (this instanceof RandomAccess ?
+                new RandomAccessSubList<>(this, fromIndex, toIndex) :
+                new SubList<>(this, fromIndex, toIndex));
+    }
+
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null :
+     * e1.equals(e2))}.)  In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this
+     * list. If so, it returns {@code true}; if not, it checks if the
+     * specified object is a list. If not, it returns {@code false}; if so,
+     * it iterates over both lists, comparing corresponding pairs of elements.
+     * If any comparison returns {@code false}, this method returns
+     * {@code false}.  If either iterator runs out of elements before the
+     * other it returns {@code false} (as the lists are of unequal length);
+     * otherwise it returns {@code true} when the iterations complete.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        ListIterator<E> e1 = listIterator();
+        ListIterator<?> e2 = ((List<?>) o).listIterator();
+        while (e1.hasNext() && e2.hasNext()) {
+            E o1 = e1.next();
+            Object o2 = e2.next();
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+        return !(e1.hasNext() || e2.hasNext());
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * @implSpec
+     * This implementation uses exactly the code that is used to define the
+     * list hash function in the documentation for the {@link List#hashCode}
+     * method.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        int hashCode = 1;
+        for (E e : this)
+            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+        return hashCode;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * <p>This method is called by the {@code clear} operation on this list
+     * and its subLists.  Overriding this method to take advantage of
+     * the internals of the list implementation can <i>substantially</i>
+     * improve the performance of the {@code clear} operation on this list
+     * and its subLists.
+     *
+     * @implSpec
+     * This implementation gets a list iterator positioned before
+     * {@code fromIndex}, and repeatedly calls {@code ListIterator.next}
+     * followed by {@code ListIterator.remove} until the entire range has
+     * been removed.  <b>Note: if {@code ListIterator.remove} requires linear
+     * time, this implementation requires quadratic time.</b>
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        ListIterator<E> it = listIterator(fromIndex);
+        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
+            it.next();
+            it.remove();
+        }
+    }
+
+    /**
+     * The number of times this list has been <i>structurally modified</i>.
+     * Structural modifications are those that change the size of the
+     * list, or otherwise perturb it in such a fashion that iterations in
+     * progress may yield incorrect results.
+     *
+     * <p>This field is used by the iterator and list iterator implementation
+     * returned by the {@code iterator} and {@code listIterator} methods.
+     * If the value of this field changes unexpectedly, the iterator (or list
+     * iterator) will throw a {@code ConcurrentModificationException} in
+     * response to the {@code next}, {@code remove}, {@code previous},
+     * {@code set} or {@code add} operations.  This provides
+     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
+     * the face of concurrent modification during iteration.
+     *
+     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
+     * wishes to provide fail-fast iterators (and list iterators), then it
+     * merely has to increment this field in its {@code add(int, E)} and
+     * {@code remove(int)} methods (and any other methods that it overrides
+     * that result in structural modifications to the list).  A single call to
+     * {@code add(int, E)} or {@code remove(int)} must add no more than
+     * one to this field, or the iterators (and list iterators) will throw
+     * bogus {@code ConcurrentModificationExceptions}.  If an implementation
+     * does not wish to provide fail-fast iterators, this field may be
+     * ignored.
+     */
+    protected transient int modCount = 0;
+
+    private void rangeCheckForAdd(int index) {
+        if (index < 0 || index > size())
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size();
+    }
+
+    /**
+     * An index-based split-by-two, lazily initialized Spliterator covering
+     * a List that access elements via {@link List#get}.
+     *
+     * If access results in an IndexOutOfBoundsException then a
+     * ConcurrentModificationException is thrown instead (since the list has
+     * been structurally modified while traversing).
+     *
+     * If the List is an instance of AbstractList then concurrent modification
+     * checking is performed using the AbstractList's modCount field.
+     */
+    static final class RandomAccessSpliterator<E> implements Spliterator<E> {
+
+        private final List<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+
+        // The following fields are valid if covering an AbstractList
+        private final AbstractList<E> alist;
+        private int expectedModCount; // initialized when fence set
+
+        RandomAccessSpliterator(List<E> list) {
+            assert list instanceof RandomAccess;
+
+            this.list = list;
+            this.index = 0;
+            this.fence = -1;
+
+            this.alist = list instanceof AbstractList ? (AbstractList<E>) list : null;
+            this.expectedModCount = alist != null ? alist.modCount : 0;
+        }
+
+        /** Create new spliterator covering the given  range */
+        private RandomAccessSpliterator(RandomAccessSpliterator<E> parent,
+                                int origin, int fence) {
+            this.list = parent.list;
+            this.index = origin;
+            this.fence = fence;
+
+            this.alist = parent.alist;
+            this.expectedModCount = parent.expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            List<E> lst = list;
+            if ((hi = fence) < 0) {
+                if (alist != null) {
+                    expectedModCount = alist.modCount;
+                }
+                hi = fence = lst.size();
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                    new RandomAccessSpliterator<>(this, lo, index = mid);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                action.accept(get(list, i));
+                checkAbstractListModCount(alist, expectedModCount);
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            List<E> lst = list;
+            int hi = getFence();
+            int i = index;
+            index = hi;
+            for (; i < hi; i++) {
+                action.accept(get(lst, i));
+            }
+            checkAbstractListModCount(alist, expectedModCount);
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static <E> E get(List<E> list, int i) {
+            try {
+                return list.get(i);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        static void checkAbstractListModCount(AbstractList<?> alist, int expectedModCount) {
+            if (alist != null && alist.modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    private static class SubList<E> extends AbstractList<E> {
+        private final AbstractList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        protected int size;
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a SubList itself.
+         */
+        public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.set(offset + index, element);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                private final ListIterator<E> i =
+                        root.listIterator(offset + index);
+
+                public boolean hasNext() {
+                    return nextIndex() < size;
+                }
+
+                public E next() {
+                    if (hasNext())
+                        return i.next();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public boolean hasPrevious() {
+                    return previousIndex() >= 0;
+                }
+
+                public E previous() {
+                    if (hasPrevious())
+                        return i.previous();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public int nextIndex() {
+                    return i.nextIndex() - offset;
+                }
+
+                public int previousIndex() {
+                    return i.previousIndex() - offset;
+                }
+
+                public void remove() {
+                    i.remove();
+                    updateSizeAndModCount(-1);
+                }
+
+                public void set(E e) {
+                    i.set(e);
+                }
+
+                public void add(E e) {
+                    i.add(e);
+                    updateSizeAndModCount(1);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
+    }
+
+    private static class RandomAccessSubList<E>
+            extends SubList<E> implements RandomAccess {
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a RandomAccessSubList itself.
+         */
+        RandomAccessSubList(AbstractList<E> root,
+                int fromIndex, int toIndex) {
+            super(root, fromIndex, toIndex);
+        }
+
+        /**
+         * Constructs a sublist of another RandomAccessSubList.
+         */
+        RandomAccessSubList(RandomAccessSubList<E> parent,
+                int fromIndex, int toIndex) {
+            super(parent, fromIndex, toIndex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        }
+    }
+}
diff --git a/android-35/java/util/AbstractMap.java b/android-35/java/util/AbstractMap.java
new file mode 100644
index 0000000..03c462d
--- /dev/null
+++ b/android-35/java/util/AbstractMap.java
@@ -0,0 +1,927 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * This class provides a skeletal implementation of the {@code Map}
+ * interface, to minimize the effort required to implement this interface.
+ *
+ * <p>To implement an unmodifiable map, the programmer needs only to extend this
+ * class and provide an implementation for the {@code entrySet} method, which
+ * returns a set-view of the map's mappings.  Typically, the returned set
+ * will, in turn, be implemented atop {@code AbstractSet}.  This set should
+ * not support the {@code add} or {@code remove} methods, and its iterator
+ * should not support the {@code remove} method.
+ *
+ * <p>To implement a modifiable map, the programmer must additionally override
+ * this class's {@code put} method (which otherwise throws an
+ * {@code UnsupportedOperationException}), and the iterator returned by
+ * {@code entrySet().iterator()} must additionally implement its
+ * {@code remove} method.
+ *
+ * <p>The programmer should generally provide a void (no argument) and map
+ * constructor, as per the recommendation in the {@code Map} interface
+ * specification.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * map being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Map
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractMap<K,V> implements Map<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractMap() {
+    }
+
+    // Query Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code entrySet().size()}.
+     */
+    public int size() {
+        return entrySet().size();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code size() == 0}.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over {@code entrySet()} searching
+     * for an entry with the specified value.  If such an entry is found,
+     * {@code true} is returned.  If the iteration terminates without
+     * finding such an entry, {@code false} is returned.  Note that this
+     * implementation requires linear time in the size of the map.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsValue(Object value) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (value==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getValue()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (value.equals(e.getValue()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over {@code entrySet()} searching
+     * for an entry with the specified key.  If such an entry is found,
+     * {@code true} is returned.  If the iteration terminates without
+     * finding such an entry, {@code false} is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsKey(Object key) {
+        Iterator<Map.Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over {@code entrySet()} searching
+     * for an entry with the specified key.  If such an entry is found,
+     * the entry's value is returned.  If the iteration terminates without
+     * finding such an entry, {@code null} is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V get(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return e.getValue();
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return e.getValue();
+            }
+        }
+        return null;
+    }
+
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public V put(K key, V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over {@code entrySet()} searching for an
+     * entry with the specified key.  If such an entry is found, its value is
+     * obtained with its {@code getValue} operation, the entry is removed
+     * from the collection (and the backing map) with the iterator's
+     * {@code remove} operation, and the saved value is returned.  If the
+     * iteration terminates without finding such an entry, {@code null} is
+     * returned.  Note that this implementation requires linear time in the
+     * size of the map; many implementations will override this method.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} if the {@code entrySet}
+     * iterator does not support the {@code remove} method and this map
+     * contains a mapping for the specified key.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V remove(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        Entry<K,V> correctEntry = null;
+        if (key==null) {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    correctEntry = e;
+            }
+        } else {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    correctEntry = e;
+            }
+        }
+
+        V oldValue = null;
+        if (correctEntry !=null) {
+            oldValue = correctEntry.getValue();
+            i.remove();
+        }
+        return oldValue;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the specified map's
+     * {@code entrySet()} collection, and calls this map's {@code put}
+     * operation once for each entry returned by the iteration.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} if this map does not support
+     * the {@code put} operation and the specified map is nonempty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation calls {@code entrySet().clear()}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} if the {@code entrySet}
+     * does not support the {@code clear} operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        entrySet().clear();
+    }
+
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     *
+     * <p>Since there is no synchronization performed while accessing these fields,
+     * it is expected that java.util.Map view classes using these fields have
+     * no non-final fields (or any fields at all except for outer-this). Adhering
+     * to this rule would make the races on these fields benign.
+     *
+     * <p>It is also imperative that implementations read the field only once,
+     * as in:
+     *
+     * <pre> {@code
+     * public Set<K> keySet() {
+     *   Set<K> ks = keySet;  // single racy read
+     *   if (ks == null) {
+     *     ks = new KeySet();
+     *     keySet = ks;
+     *   }
+     *   return ks;
+     * }
+     *}</pre>
+     */
+    transient Set<K>        keySet;
+    transient Collection<V> values;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a set that subclasses {@link AbstractSet}.
+     * The subclass's iterator method returns a "wrapper object" over this
+     * map's {@code entrySet()} iterator.  The {@code size} method
+     * delegates to this map's {@code size} method and the
+     * {@code contains} method delegates to this map's
+     * {@code containsKey} method.
+     *
+     * <p>The set is created the first time this method is called,
+     * and returned in response to all subsequent calls.  No synchronization
+     * is performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same set.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new AbstractSet<K>() {
+                public Iterator<K> iterator() {
+                    return new Iterator<K>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public K next() {
+                            return i.next().getKey();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object k) {
+                    return AbstractMap.this.containsKey(k);
+                }
+            };
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a collection that subclasses {@link
+     * AbstractCollection}.  The subclass's iterator method returns a
+     * "wrapper object" over this map's {@code entrySet()} iterator.
+     * The {@code size} method delegates to this map's {@code size}
+     * method and the {@code contains} method delegates to this map's
+     * {@code containsValue} method.
+     *
+     * <p>The collection is created the first time this method is called, and
+     * returned in response to all subsequent calls.  No synchronization is
+     * performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same collection.
+     */
+    public Collection<V> values() {
+        Collection<V> vals = values;
+        if (vals == null) {
+            vals = new AbstractCollection<V>() {
+                public Iterator<V> iterator() {
+                    return new Iterator<V>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public V next() {
+                            return i.next().getValue();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object v) {
+                    return AbstractMap.this.containsValue(v);
+                }
+            };
+            values = vals;
+        }
+        return vals;
+    }
+
+    public abstract Set<Entry<K,V>> entrySet();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps {@code m1} and
+     * {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the
+     * {@code equals} method works properly across different implementations
+     * of the {@code Map} interface.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this map;
+     * if so it returns {@code true}.  Then, it checks if the specified
+     * object is a map whose size is identical to the size of this map; if
+     * not, it returns {@code false}.  If so, it iterates over this map's
+     * {@code entrySet} collection, and checks that the specified map
+     * contains each mapping that this map contains.  If the specified map
+     * fails to contain such a mapping, {@code false} is returned.  If the
+     * iteration completes, {@code true} is returned.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map<?, ?> m))
+            return false;
+        if (m.size() != size())
+            return false;
+
+        try {
+            for (Entry<K, V> e : entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(m.get(key) == null && m.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(m.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException | NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * {@code entrySet()} view.  This ensures that {@code m1.equals(m2)}
+     * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
+     * {@code m1} and {@code m2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @implSpec
+     * This implementation iterates over {@code entrySet()}, calling
+     * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
+     * set, and adding up the results.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        for (Entry<K, V> entry : entrySet())
+            h += entry.hashCode();
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string representation
+     * consists of a list of key-value mappings in the order returned by the
+     * map's {@code entrySet} view's iterator, enclosed in braces
+     * ({@code "{}"}).  Adjacent mappings are separated by the characters
+     * {@code ", "} (comma and space).  Each key-value mapping is rendered as
+     * the key followed by an equals sign ({@code "="}) followed by the
+     * associated value.  Keys and values are converted to strings as by
+     * {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (! i.hasNext())
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (;;) {
+            Entry<K,V> e = i.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key);
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value);
+            if (! i.hasNext())
+                return sb.append('}').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this {@code AbstractMap} instance: the keys
+     * and values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    protected Object clone() throws CloneNotSupportedException {
+        AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
+        result.keySet = null;
+        result.values = null;
+        return result;
+    }
+
+    /**
+     * Utility method for SimpleEntry and SimpleImmutableEntry.
+     * Test for equality, checking for nulls.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    private static boolean eq(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    // Implementation Note: SimpleEntry and SimpleImmutableEntry
+    // are distinct unrelated classes, even though they share
+    // some code. Since you can't add or subtract final-ness
+    // of a field in a subclass, they can't share representations,
+    // and the amount of duplicated code is too small to warrant
+    // exposing a common abstract class.
+
+
+    /**
+     * An Entry maintaining a key and a value.  The value may be
+     * changed using the {@code setValue} method. Instances of
+     * this class are not associated with any map nor with any
+     * map's entry-set view.
+     *
+     * @apiNote
+     * This class facilitates the process of building custom map
+     * implementations. For example, it may be convenient to return
+     * arrays of {@code SimpleEntry} instances in method
+     * {@code Map.entrySet().toArray}.
+     *
+     * @param <K> the type of key
+     * @param <V> the type of the value
+     *
+     * @since 1.6
+     */
+    public static class SimpleEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -8499721149061103585L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final K key;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value.
+         *
+         * @param value new value to be stored in this entry
+         * @return the old value corresponding to the entry
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            return o instanceof Map.Entry<?, ?> e
+                    && eq(key, e.getKey())
+                    && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("{@code =}")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+
+    }
+
+    /**
+     * An unmodifiable Entry maintaining a key and a value.  This class
+     * does not support the {@code setValue} method. Instances of
+     * this class are not associated with any map nor with any map's
+     * entry-set view.
+     *
+     * @apiNote
+     * Instances of this class are not necessarily immutable, as the key
+     * and value may be mutable. An instance of <i>this specific class</i>
+     * is unmodifiable, because the key and value references cannot be
+     * changed. A reference of this <i>type</i> may not be unmodifiable,
+     * as a subclass may be modifiable or may provide the appearance of modifiability.
+     * <p>
+     * This class may be convenient in methods that return thread-safe snapshots of
+     * key-value mappings. For alternatives, see the
+     * {@link Map#entry Map::entry} and {@link Map.Entry#copyOf Map.Entry::copyOf}
+     * methods.
+     *
+     * @param <K> the type of the keys
+     * @param <V> the type of the value
+     * @since 1.6
+     */
+    public static class SimpleImmutableEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 7138329143949025153L;
+
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        private final K key;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        private final V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleImmutableEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  This implementation simply throws
+         * {@code UnsupportedOperationException}, as this class implements
+         * an unmodifiable map entry.
+         *
+         * @implSpec
+         * The implementation in this class always throws {@code UnsupportedOperationException}.
+         *
+         * @param value new value to be stored in this entry
+         * @return (Does not return)
+         * @throws UnsupportedOperationException always
+         */
+        public V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            return o instanceof Map.Entry<?, ?> e
+                    && eq(key, e.getKey())
+                    && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("{@code =}")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    /**
+     * Delegates all Collection methods to the provided non-sequenced map view,
+     * except add() and addAll(), which throw UOE. This provides the common
+     * implementation of each of the sequenced views of the SequencedMap.
+     * Each view implementation is a subclass that provides an instance of the
+     * non-sequenced view as a delegate and an implementation of reversed().
+     * Each view also inherits the default implementations for the sequenced
+     * methods from SequencedCollection or SequencedSet.
+     * <p>
+     * Ideally this would be a private class within SequencedMap, but private
+     * classes aren't permitted within interfaces.
+     * <p>
+     * The non-sequenced map view is obtained by calling the abstract view()
+     * method for each operation.
+     *
+     * @param <E> the view's element type
+     */
+    /* non-public */ abstract static class ViewCollection<E> implements Collection<E> {
+        UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+        abstract Collection<E> view();
+
+        public boolean add(E t) { throw uoe(); }
+        public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        public void clear() { view().clear(); }
+        public boolean contains(Object o) { return view().contains(o); }
+        public boolean containsAll(Collection<?> c) { return view().containsAll(c); }
+        public void forEach(Consumer<? super E> c) { view().forEach(c); }
+        public boolean isEmpty() { return view().isEmpty(); }
+        public Iterator<E> iterator() { return view().iterator(); }
+        public Stream<E> parallelStream() { return view().parallelStream(); }
+        public boolean remove(Object o) { return view().remove(o); }
+        public boolean removeAll(Collection<?> c) { return view().removeAll(c); }
+        public boolean removeIf(Predicate<? super E> filter) { return view().removeIf(filter); }
+        public boolean retainAll(Collection<?> c) { return view().retainAll(c); }
+        public int size() { return view().size(); }
+        public Spliterator<E> spliterator() { return view().spliterator(); }
+        public Stream<E> stream() { return view().stream(); }
+        public Object[] toArray() { return view().toArray(); }
+        public <T> T[] toArray(IntFunction<T[]> generator) { return view().toArray(generator); }
+        public <T> T[] toArray(T[] a) { return view().toArray(a); }
+        public String toString() { return view().toString(); }
+    }
+}
diff --git a/android-35/java/util/AbstractQueue.java b/android-35/java/util/AbstractQueue.java
new file mode 100644
index 0000000..dd31ed2
--- /dev/null
+++ b/android-35/java/util/AbstractQueue.java
@@ -0,0 +1,192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * This class provides skeletal implementations of some {@link Queue}
+ * operations. The implementations in this class are appropriate when
+ * the base implementation does <em>not</em> allow {@code null}
+ * elements.  Methods {@link #add add}, {@link #remove remove}, and
+ * {@link #element element} are based on {@link #offer offer}, {@link
+ * #poll poll}, and {@link #peek peek}, respectively, but throw
+ * exceptions instead of indicating failure via {@code false} or
+ * {@code null} returns.
+ *
+ * <p>A {@code Queue} implementation that extends this class must
+ * minimally define a method {@link Queue#offer} which does not permit
+ * insertion of {@code null} elements, along with methods {@link
+ * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and
+ * {@link Collection#iterator}.  Typically, additional methods will be
+ * overridden as well.  If these requirements cannot be met, consider
+ * instead subclassing {@link AbstractCollection}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public abstract class AbstractQueue<E>
+    extends AbstractCollection<E>
+    implements Queue<E> {
+
+    /**
+     * Constructor for use by subclasses.
+     */
+    protected AbstractQueue() {
+    }
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * <p>This implementation returns {@code true} if {@code offer} succeeds,
+     * else throws an {@code IllegalStateException}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @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 and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    public boolean add(E e) {
+        if (offer(e))
+            return true;
+        else
+            throw new IllegalStateException("Queue full");
+    }
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll poll} only in that it throws an exception if this
+     * queue is empty.
+     *
+     * <p>This implementation returns the result of {@code poll}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E remove() {
+        E x = poll();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception if
+     * this queue is empty.
+     *
+     * <p>This implementation returns the result of {@code peek}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E element() {
+        E x = peek();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     *
+     * <p>This implementation repeatedly invokes {@link #poll poll} until it
+     * returns {@code null}.
+     */
+    public void clear() {
+        while (poll() != null)
+            ;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this
+     * queue.  Attempts to addAll of a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * <p>This implementation iterates over the specified collection,
+     * and adds each element returned by the iterator to this
+     * queue, in turn.  A runtime exception encountered while
+     * trying to add an element (including, in particular, a
+     * {@code null} element) may result in only some of the elements
+     * having been successfully added when the associated exception is
+     * thrown.
+     *
+     * @param c collection containing elements to be added to this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this queue
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this queue does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         queue, or if the specified collection is this queue
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+}
diff --git a/android-35/java/util/AbstractSequentialList.java b/android-35/java/util/AbstractSequentialList.java
new file mode 100644
index 0000000..f59ed18
--- /dev/null
+++ b/android-35/java/util/AbstractSequentialList.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the {@code List}
+ * interface to minimize the effort required to implement this interface
+ * backed by a "sequential access" data store (such as a linked list).  For
+ * random access data (such as an array), {@code AbstractList} should be used
+ * in preference to this class.<p>
+ *
+ * This class is the opposite of the {@code AbstractList} class in the sense
+ * that it implements the "random access" methods ({@code get(int index)},
+ * {@code set(int index, E element)}, {@code add(int index, E element)} and
+ * {@code remove(int index)}) on top of the list's list iterator, instead of
+ * the other way around.<p>
+ *
+ * To implement a list the programmer needs only to extend this class and
+ * provide implementations for the {@code listIterator} and {@code size}
+ * methods.  For an unmodifiable list, the programmer need only implement the
+ * list iterator's {@code hasNext}, {@code next}, {@code hasPrevious},
+ * {@code previous} and {@code index} methods.<p>
+ *
+ * For a modifiable list the programmer should additionally implement the list
+ * iterator's {@code set} method.  For a variable-size list the programmer
+ * should additionally implement the list iterator's {@code remove} and
+ * {@code add} methods.<p>
+ *
+ * The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the {@code Collection} interface
+ * specification.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see AbstractList
+ * @see AbstractCollection
+ * @since 1.2
+ */
+
+public abstract class AbstractSequentialList<E> extends AbstractList<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSequentialList() {
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with {@code listIterator(index)}).  Then, it gets
+     * the element using {@code ListIterator.next} and returns it.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        try {
+            return listIterator(index).next();
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with {@code listIterator(index)}).  Then, it gets
+     * the current element using {@code ListIterator.next} and replaces it
+     * with {@code ListIterator.set}.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the list iterator does not
+     * implement the {@code set} operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E oldVal = e.next();
+            e.set(element);
+            return oldVal;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with {@code listIterator(index)}).  Then, it
+     * inserts the specified element with {@code ListIterator.add}.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the list iterator does not
+     * implement the {@code add} operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        try {
+            listIterator(index).add(element);
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with {@code listIterator(index)}).  Then, it removes
+     * the element with {@code ListIterator.remove}.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the list iterator does not
+     * implement the {@code remove} operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E outCast = e.next();
+            e.remove();
+            return outCast;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * <p>This implementation gets an iterator over the specified collection and
+     * a list iterator over this list pointing to the indexed element (with
+     * {@code listIterator(index)}).  Then, it iterates over the specified
+     * collection, inserting the elements obtained from the iterator into this
+     * list, one at a time, using {@code ListIterator.add} followed by
+     * {@code ListIterator.next} (to skip over the added element).
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the list iterator returned by
+     * the {@code listIterator} method does not implement the {@code add}
+     * operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        try {
+            boolean modified = false;
+            ListIterator<E> e1 = listIterator(index);
+            for (E e : c) {
+                e1.add(e);
+                modified = true;
+            }
+            return modified;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list (in proper
+     * sequence).<p>
+     *
+     * This implementation merely returns a list iterator over the list.
+     *
+     * @return an iterator over the elements in this list (in proper sequence)
+     */
+    public Iterator<E> iterator() {
+        return listIterator();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @param  index index of first element to be returned from the list
+     *         iterator (by a call to the {@code next} method)
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract ListIterator<E> listIterator(int index);
+}
diff --git a/android-35/java/util/AbstractSet.java b/android-35/java/util/AbstractSet.java
new file mode 100644
index 0000000..80d4c5e
--- /dev/null
+++ b/android-35/java/util/AbstractSet.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the {@code Set}
+ * interface to minimize the effort required to implement this
+ * interface. <p>
+ *
+ * The process of implementing a set by extending this class is identical
+ * to that of implementing a Collection by extending AbstractCollection,
+ * except that all of the methods and constructors in subclasses of this
+ * class must obey the additional constraints imposed by the {@code Set}
+ * interface (for instance, the add method must not permit addition of
+ * multiple instances of an object to a set).<p>
+ *
+ * Note that this class does not override any of the implementations from
+ * the {@code AbstractCollection} class.  It merely adds implementations
+ * for {@code equals} and {@code hashCode}.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see AbstractCollection
+ * @see Set
+ * @since 1.2
+ */
+
+public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSet() {
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.  This ensures that the {@code equals} method works
+     * properly across different implementations of the {@code Set}
+     * interface.<p>
+     *
+     * This implementation first checks if the specified object is this
+     * set; if so it returns {@code true}.  Then, it checks if the
+     * specified object is a set whose size is identical to the size of
+     * this set; if not, it returns false.  If so, it returns
+     * {@code containsAll((Collection) o)}.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        if (c.size() != size())
+            return false;
+        try {
+            return containsAll(c);
+        } catch (ClassCastException | NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * <p>This implementation iterates over the set, calling the
+     * {@code hashCode} method on each element in the set, and adding up
+     * the results.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        Iterator<E> i = iterator();
+        while (i.hasNext()) {
+            E obj = i.next();
+            if (obj != null)
+                h += obj.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * <p>This implementation determines which is the smaller of this set
+     * and the specified collection, by invoking the {@code size}
+     * method on each.  If this set has fewer elements, then the
+     * implementation iterates over this set, checking each element
+     * returned by the iterator in turn to see if it is contained in
+     * the specified collection.  If it is so contained, it is removed
+     * from this set with the iterator's {@code remove} method.  If
+     * the specified collection has fewer elements, then the
+     * implementation iterates over the specified collection, removing
+     * from this set each element returned by the iterator, using this
+     * set's {@code remove} method.
+     *
+     * <p>Note that this implementation will throw an
+     * {@code UnsupportedOperationException} if the iterator returned by the
+     * {@code iterator} method does not implement the {@code remove} method.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+
+        if (size() > c.size()) {
+            for (Object e : c)
+                modified |= remove(e);
+        } else {
+            for (Iterator<?> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+}
diff --git a/android-35/java/util/ArrayDeque.java b/android-35/java/util/ArrayDeque.java
new file mode 100644
index 0000000..d4406b4
--- /dev/null
+++ b/android-35/java/util/ArrayDeque.java
@@ -0,0 +1,1243 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Josh Bloch of Google Inc. and released to the public domain,
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * Resizable-array implementation of the {@link Deque} interface.  Array
+ * deques have no capacity restrictions; they grow as necessary to support
+ * usage.  They are not thread-safe; in the absence of external
+ * synchronization, they do not support concurrent access by multiple threads.
+ * Null elements are prohibited.  This class is likely to be faster than
+ * {@link Stack} when used as a stack, and faster than {@link LinkedList}
+ * when used as a queue.
+ *
+ * <p>Most {@code ArrayDeque} operations run in amortized constant time.
+ * Exceptions include
+ * {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence},
+ * {@link #removeLastOccurrence removeLastOccurrence},
+ * {@link #contains contains},
+ * {@link #iterator iterator.remove()},
+ * and the bulk operations, all of which run in linear time.
+ *
+ * <p>The iterators returned by this class's {@link #iterator() iterator}
+ * method are <em>fail-fast</em>: If the deque is modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will generally throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the
+ * future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em> methods of the
+ * {@link Collection}, {@link SequencedCollection}, and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @param <E> the type of elements held in this deque
+ * @since   1.6
+ */
+public class ArrayDeque<E> extends AbstractCollection<E>
+                           implements Deque<E>, Cloneable, Serializable
+{
+    /*
+     * VMs excel at optimizing simple array loops where indices are
+     * incrementing or decrementing over a valid slice, e.g.
+     *
+     * for (int i = start; i < end; i++) ... elements[i]
+     *
+     * Because in a circular array, elements are in general stored in
+     * two disjoint such slices, we help the VM by writing unusual
+     * nested loops for all traversals over the elements.  Having only
+     * one hot inner loop body instead of two or three eases human
+     * maintenance and encourages VM loop inlining into the caller.
+     */
+
+    /**
+     * The array in which the elements of the deque are stored.
+     * All array cells not holding deque elements are always null.
+     * The array always has at least one null slot (at tail).
+     */
+    transient Object[] elements;
+
+    /**
+     * The index of the element at the head of the deque (which is the
+     * element that would be removed by remove() or pop()); or an
+     * arbitrary number 0 <= head < elements.length equal to tail if
+     * the deque is empty.
+     */
+    transient int head;
+
+    /**
+     * The index at which the next element would be added to the tail
+     * of the deque (via addLast(E), add(E), or push(E));
+     * elements[tail] is always null.
+     */
+    transient int tail;
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of this deque by at least the given amount.
+     *
+     * @param needed the required minimum extra capacity; must be positive
+     */
+    private void grow(int needed) {
+        // overflow-conscious code
+        final int oldCapacity = elements.length;
+        int newCapacity;
+        // Double capacity if small; else grow by 50%
+        int jump = (oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1);
+        if (jump < needed
+            || (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0)
+            newCapacity = newCapacity(needed, jump);
+        // Android-added: preserve reference to the old storage to nullify it later.
+        final Object[] oldElements = elements;
+        final Object[] es = elements = Arrays.copyOf(elements, newCapacity);
+        // Exceptionally, here tail == head needs to be disambiguated
+        if (tail < head || (tail == head && es[head] != null)) {
+            // wrap around; slide first leg forward to end of array
+            int newSpace = newCapacity - oldCapacity;
+            System.arraycopy(es, head,
+                             es, head + newSpace,
+                             oldCapacity - head);
+            for (int i = head, to = (head += newSpace); i < to; i++)
+                es[i] = null;
+        }
+        // Android-added: Clear old array instance that's about to become eligible for GC.
+        // This ensures that array elements can be eligible for garbage collection even
+        // before the array itself is recognized as being eligible; the latter might
+        // take a while in some GC implementations, if the array instance is longer lived
+        // (its liveness rarely checked) than some of its contents.
+        Arrays.fill(oldElements, null);
+    }
+
+    /** Capacity calculation for edge conditions, especially overflow. */
+    private int newCapacity(int needed, int jump) {
+        final int oldCapacity = elements.length, minCapacity;
+        if ((minCapacity = oldCapacity + needed) - MAX_ARRAY_SIZE > 0) {
+            if (minCapacity < 0)
+                throw new IllegalStateException("Sorry, deque too big");
+            return Integer.MAX_VALUE;
+        }
+        if (needed > jump)
+            return minCapacity;
+        return (oldCapacity + jump - MAX_ARRAY_SIZE < 0)
+            ? oldCapacity + jump
+            : MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold 16 elements.
+     */
+    public ArrayDeque() {
+        elements = new Object[16 + 1];
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold the specified number of elements.
+     *
+     * @param numElements lower bound on initial capacity of the deque
+     */
+    public ArrayDeque(int numElements) {
+        elements =
+            new Object[(numElements < 1) ? 1 :
+                       (numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                       numElements + 1];
+    }
+
+    /**
+     * Constructs a deque containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.  (The first element returned by the collection's
+     * iterator becomes the first element, or <i>front</i> of the
+     * deque.)
+     *
+     * @param c the collection whose elements are to be placed into the deque
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayDeque(Collection<? extends E> c) {
+        this(c.size());
+        copyElements(c);
+    }
+
+    /**
+     * Circularly increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Circularly decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
+    }
+
+    /**
+     * Circularly adds the given distance to index i, mod modulus.
+     * Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
+     * @return index 0 <= i < modulus
+     */
+    static final int inc(int i, int distance, int modulus) {
+        if ((i += distance) - modulus >= 0) i -= modulus;
+        return i;
+    }
+
+    /**
+     * Subtracts j from i, mod modulus.
+     * Index i must be logically ahead of index j.
+     * Precondition: 0 <= i < modulus, 0 <= j < modulus.
+     * @return the "circular distance" from j to i; corner case i == j
+     * is disambiguated to "empty", returning 0.
+     */
+    static final int sub(int i, int j, int modulus) {
+        if ((i -= j) < 0) i += modulus;
+        return i;
+    }
+
+    /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static final <E> E elementAt(Object[] es, int i) {
+        return (E) es[i];
+    }
+
+    /**
+     * A version of elementAt that checks for null elements.
+     * This check doesn't catch all possible comodifications,
+     * but does catch ones that corrupt traversal.
+     */
+    static final <E> E nonNullElementAt(Object[] es, int i) {
+        @SuppressWarnings("unchecked") E e = (E) es[i];
+        if (e == null)
+            throw new ConcurrentModificationException();
+        return e;
+    }
+
+    // The main insertion and extraction methods are addFirst,
+    // addLast, pollFirst, pollLast. The other methods are defined in
+    // terms of these.
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        final Object[] es = elements;
+        es[head = dec(head, es.length)] = e;
+        if (head == tail)
+            grow(1);
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        final Object[] es = elements;
+        es[tail] = e;
+        if (head == (tail = inc(tail, es.length)))
+            grow(1);
+    }
+
+    /**
+     * Adds all of the elements in the specified collection at the end
+     * of this deque, as if by calling {@link #addLast} on each one,
+     * in the order that they are returned by the collection's iterator.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        final int s, needed;
+        if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
+            grow(needed);
+        copyElements(c);
+        return size() > s;
+    }
+
+    private void copyElements(Collection<? extends E> c) {
+        c.forEach(this::addLast);
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E e = pollFirst();
+        if (e == null)
+            throw new NoSuchElementException();
+        return e;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E e = pollLast();
+        if (e == null)
+            throw new NoSuchElementException();
+        return e;
+    }
+
+    public E pollFirst() {
+        final Object[] es;
+        final int h;
+        E e = elementAt(es = elements, h = head);
+        if (e != null) {
+            es[h] = null;
+            head = inc(h, es.length);
+        }
+        return e;
+    }
+
+    public E pollLast() {
+        final Object[] es;
+        final int t;
+        E e = elementAt(es = elements, t = dec(tail, es.length));
+        if (e != null)
+            es[tail = t] = null;
+        return e;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        E e = elementAt(elements, head);
+        if (e == null)
+            throw new NoSuchElementException();
+        return e;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        final Object[] es = elements;
+        E e = elementAt(es, dec(tail, es.length));
+        if (e == null)
+            throw new NoSuchElementException();
+        return e;
+    }
+
+    public E peekFirst() {
+        return elementAt(elements, head);
+    }
+
+    public E peekLast() {
+        final Object[] es;
+        return elementAt(es = elements, dec(tail, es.length));
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        if (o != null) {
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o != null) {
+            final Object[] es = elements;
+            for (int i = tail, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length, to = end) {
+                for (i--; i > to - 1; i--)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
+            }
+        }
+        return false;
+    }
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     *
+     * This method differs from {@link #poll() poll()} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E poll() {
+        return pollFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek peek} only in
+     * that it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque, or returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E peek() {
+        return peekFirst();
+    }
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque.  In other
+     * words, inserts the element at the front of this deque.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws NullPointerException if the specified element is null
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    /**
+     * Removes the element at the specified position in the elements array.
+     * This can result in forward or backwards motion of array elements.
+     * We optimize for least element motion.
+     *
+     * <p>This method is called delete rather than remove to emphasize
+     * that its semantics differ from those of {@link List#remove(int)}.
+     *
+     * @return true if elements near tail moved backwards
+     */
+    boolean delete(int i) {
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int h, t;
+        // number of elements before to-be-deleted elt
+        final int front = sub(i, h = head, capacity);
+        // number of elements after to-be-deleted elt
+        final int back = sub(t = tail, i, capacity) - 1;
+        if (front < back) {
+            // move front elements forwards
+            if (h <= i) {
+                System.arraycopy(es, h, es, h + 1, front);
+            } else { // Wrap around
+                System.arraycopy(es, 0, es, 1, i);
+                es[0] = es[capacity - 1];
+                System.arraycopy(es, h, es, h + 1, front - (i + 1));
+            }
+            es[h] = null;
+            head = inc(h, capacity);
+            return false;
+        } else {
+            // move back elements backwards
+            tail = dec(t, capacity);
+            if (i <= tail) {
+                System.arraycopy(es, i + 1, es, i, back);
+            } else { // Wrap around
+                System.arraycopy(es, i + 1, es, i, capacity - (i + 1));
+                es[capacity - 1] = es[0];
+                System.arraycopy(es, 1, es, 0, t - 1);
+            }
+            es[tail] = null;
+            return true;
+        }
+    }
+
+    // *** Collection Methods ***
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        return sub(tail, head, elements.length);
+    }
+
+    /**
+     * Returns {@code true} if this deque contains no elements.
+     *
+     * @return {@code true} if this deque contains no elements
+     */
+    public boolean isEmpty() {
+        return head == tail;
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque.  The elements
+     * will be ordered from first (head) to last (tail).  This is the same
+     * order that elements would be dequeued (via successive calls to
+     * {@link #remove} or popped (via successive calls to {@link #pop}).
+     *
+     * @return an iterator over the elements in this deque
+     */
+    public Iterator<E> iterator() {
+        return new DeqIterator();
+    }
+
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    private class DeqIterator implements Iterator<E> {
+        /** Index of element to be returned by subsequent call to next. */
+        int cursor;
+
+        /** Number of elements yet to be returned. */
+        int remaining = size();
+
+        /**
+         * Index of element returned by most recent call to next.
+         * Reset to -1 if element is deleted by a call to remove.
+         */
+        int lastRet = -1;
+
+        DeqIterator() { cursor = head; }
+
+        public final boolean hasNext() {
+            return remaining > 0;
+        }
+
+        public E next() {
+            if (remaining <= 0)
+                throw new NoSuchElementException();
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = inc(lastRet = cursor, es.length);
+            remaining--;
+            return e;
+        }
+
+        void postDelete(boolean leftShifted) {
+            if (leftShifted)
+                cursor = dec(cursor, elements.length);
+        }
+
+        public final void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            postDelete(delete(lastRet));
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(tail, cursor, es.length) != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != tail)
+                        throw new ConcurrentModificationException();
+                    lastRet = dec(end, es.length);
+                    break;
+                }
+            }
+        }
+    }
+
+    private class DescendingIterator extends DeqIterator {
+        DescendingIterator() { cursor = dec(tail, elements.length); }
+
+        public final E next() {
+            if (remaining <= 0)
+                throw new NoSuchElementException();
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = dec(lastRet = cursor, es.length);
+            remaining--;
+            return e;
+        }
+
+        void postDelete(boolean leftShifted) {
+            if (!leftShifted)
+                cursor = inc(cursor, elements.length);
+        }
+
+        public final void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(cursor, head, es.length) + 1 != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length - 1, to = end) {
+                // hotspot generates faster code than for: i >= to !
+                for (; i > to - 1; i--)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != head)
+                        throw new ConcurrentModificationException();
+                    lastRet = end;
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new DeqSpliterator();
+    }
+
+    final class DeqSpliterator implements Spliterator<E> {
+        private int fence;      // -1 until first use
+        private int cursor;     // current index, modified on traverse/split
+
+        /** Constructs late-binding spliterator over all elements. */
+        DeqSpliterator() {
+            this.fence = -1;
+        }
+
+        /** Constructs spliterator over the given range. */
+        DeqSpliterator(int origin, int fence) {
+            // assert 0 <= origin && origin < elements.length;
+            // assert 0 <= fence && fence < elements.length;
+            this.cursor = origin;
+            this.fence = fence;
+        }
+
+        /** Ensures late-binding initialization; then returns fence. */
+        private int getFence() { // force initialization
+            int t;
+            if ((t = fence) < 0) {
+                t = fence = tail;
+                cursor = head;
+            }
+            return t;
+        }
+
+        public DeqSpliterator trySplit() {
+            final Object[] es = elements;
+            final int i, n;
+            return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
+                ? null
+                : new DeqSpliterator(i, cursor = inc(i, n, es.length));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            final int end = getFence(), cursor = this.cursor;
+            final Object[] es = elements;
+            if (cursor != end) {
+                this.cursor = end;
+                // null check at both ends of range is sufficient
+                if (es[cursor] == null || es[dec(end, es.length)] == null)
+                    throw new ConcurrentModificationException();
+                for (int i = cursor, to = (i <= end) ? end : es.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(elementAt(es, i));
+                    if (to == end) break;
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Object[] es = elements;
+            if (fence < 0) { fence = tail; cursor = head; } // late-binding
+            final int i;
+            if ((i = cursor) == fence)
+                return false;
+            E e = nonNullElementAt(es, i);
+            cursor = inc(i, es.length);
+            action.accept(e);
+            return true;
+        }
+
+        public long estimateSize() {
+            return sub(getFence(), cursor, elements.length);
+        }
+
+        public int characteristics() {
+            return Spliterator.NONNULL
+                | Spliterator.ORDERED
+                | Spliterator.SIZED
+                | Spliterator.SUBSIZED;
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                action.accept(elementAt(es, i));
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
+            }
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final Object[] es = elements;
+        // Optimize for initial run of survivors
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    return bulkRemoveModified(filter, i);
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
+            }
+        }
+        return false;
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but writers still get CME), so traverse once to find
+     * elements to delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int end = tail;
+        final long[] deathRow = nBits(sub(end, beg, capacity));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        if (end != tail) throw new ConcurrentModificationException();
+        circularClear(es, tail = w, end);
+        return true;
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i]))
+                        return true;
+                if (to == end) break;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque contained the specified element
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        circularClear(elements, head, tail);
+        head = tail = 0;
+    }
+
+    /**
+     * Nulls out slots starting at array index i, up to index end.
+     * Condition i == end means "empty" - nothing to do.
+     */
+    private static void circularClear(Object[] es, int i, int end) {
+        // assert 0 <= i && i < es.length;
+        // assert 0 <= end && end < es.length;
+        for (int to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++) es[i] = null;
+            if (to == end) break;
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        return toArray(Object[].class);
+    }
+
+    private <T> T[] toArray(Class<T[]> klazz) {
+        final Object[] es = elements;
+        final T[] a;
+        final int head = this.head, tail = this.tail, end;
+        if ((end = tail + ((head <= tail) ? 0 : es.length)) >= 0) {
+            // Uses null extension feature of copyOfRange
+            a = Arrays.copyOfRange(es, head, end, klazz);
+        } else {
+            // integer overflow!
+            a = Arrays.copyOfRange(es, 0, end - head, klazz);
+            System.arraycopy(es, head, a, 0, es.length - head);
+        }
+        if (end != tail)
+            System.arraycopy(es, 0, a, es.length - head, tail);
+        return a;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque in
+     * proper sequence (from first to last element); the runtime type of the
+     * returned array is that of the specified array.  If the deque fits in
+     * the specified array, it is returned therein.  Otherwise, a new array
+     * is allocated with the runtime type of the specified array and the
+     * size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final int size;
+        if ((size = size()) > a.length)
+            return toArray((Class<T[]>) a.getClass());
+        final Object[] es = elements;
+        for (int i = head, j = 0, len = Math.min(size, es.length - i);
+             ; i = 0, len = tail) {
+            System.arraycopy(es, i, a, j, len);
+            if ((j += len) == size) break;
+        }
+        if (size < a.length)
+            a[size] = null;
+        return a;
+    }
+
+    // *** Object methods ***
+
+    /**
+     * Returns a copy of this deque.
+     *
+     * @return a copy of this deque
+     */
+    public ArrayDeque<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
+            result.elements = Arrays.copyOf(elements, elements.length);
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 2340985798034038923L;
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The current size ({@code int}) of the deque,
+     * followed by all of its elements (each an object reference) in
+     * first-to-last order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size());
+
+        // Write out elements in order.
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                s.writeObject(es[i]);
+            if (to == end) break;
+        }
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in size and allocate array
+        int size = s.readInt();
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size + 1);
+        elements = new Object[size + 1];
+        this.tail = size;
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            elements[i] = s.readObject();
+    }
+
+    /** debugging */
+    void checkInvariants() {
+        // Use head and tail fields with empty slot at tail strategy.
+        // head == tail disambiguates to "empty".
+        try {
+            int capacity = elements.length;
+            // assert 0 <= head && head < capacity;
+            // assert 0 <= tail && tail < capacity;
+            // assert capacity > 0;
+            // assert size() < capacity;
+            // assert head == tail || elements[head] != null;
+            // assert elements[tail] == null;
+            // assert head == tail || elements[dec(tail, capacity)] != null;
+        } catch (Throwable t) {
+            System.err.printf("head=%d tail=%d capacity=%d%n",
+                              head, tail, elements.length);
+            System.err.printf("elements=%s%n",
+                              Arrays.toString(elements));
+            throw t;
+        }
+    }
+
+}
diff --git a/android-35/java/util/ArrayList.java b/android-35/java/util/ArrayList.java
new file mode 100644
index 0000000..a418e64
--- /dev/null
+++ b/android-35/java/util/ArrayList.java
@@ -0,0 +1,1831 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * Resizable-array implementation of the {@code List} interface.  Implements
+ * all optional list operations, and permits all elements, including
+ * {@code null}.  In addition to implementing the {@code List} interface,
+ * this class provides methods to manipulate the size of the array that is
+ * used internally to store the list.  (This class is roughly equivalent to
+ * {@code Vector}, except that it is unsynchronized.)
+ *
+ * <p>The {@code size}, {@code isEmpty}, {@code get}, {@code set},
+ * {@code iterator}, and {@code listIterator} operations run in constant
+ * time.  The {@code add} operation runs in <i>amortized constant time</i>,
+ * that is, adding n elements requires O(n) time.  All of the other operations
+ * run in linear time (roughly speaking).  The constant factor is low compared
+ * to that for the {@code LinkedList} implementation.
+ *
+ * <p>Each {@code ArrayList} instance has a <i>capacity</i>.  The capacity is
+ * the size of the array used to store the elements in the list.  It is always
+ * at least as large as the list size.  As elements are added to an ArrayList,
+ * its capacity grows automatically.  The details of the growth policy are not
+ * specified beyond the fact that adding an element has constant amortized
+ * time cost.
+ *
+ * <p>An application can increase the capacity of an {@code ArrayList} instance
+ * before adding a large number of elements using the {@code ensureCapacity}
+ * operation.  This may reduce the amount of incremental reallocation.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an {@code ArrayList} instance concurrently,
+ * and at least one of the threads modifies the list structurally, it
+ * <i>must</i> be synchronized externally.  (A structural modification is
+ * any operation that adds or deletes one or more elements, or explicitly
+ * resizes the backing array; merely setting the value of an element is not
+ * a structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
+ *
+ * <p id="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:
+ * if the list is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) add} methods, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of
+ * concurrent modification, the iterator fails quickly and cleanly, rather
+ * than risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     List
+ * @see     LinkedList
+ * @see     Vector
+ * @since   1.2
+ */
+// Android-changed: CME in iterators;
+/*
+ * - AOSP commit b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194
+ *   Fix ConcurrentModificationException in ArrayList iterators.
+ */
+public class ArrayList<E> extends AbstractList<E>
+        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    @java.io.Serial
+    private static final long serialVersionUID = 8683452581122892189L;
+
+    /**
+     * Default initial capacity.
+     */
+    private static final int DEFAULT_CAPACITY = 10;
+
+    /**
+     * Shared empty array instance used for empty instances.
+     */
+    private static final Object[] EMPTY_ELEMENTDATA = {};
+
+    /**
+     * Shared empty array instance used for default sized empty instances. We
+     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
+     * first element is added.
+     */
+    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
+
+    /**
+     * The array buffer into which the elements of the ArrayList are stored.
+     * The capacity of the ArrayList is the length of this array buffer. Any
+     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
+     * will be expanded to DEFAULT_CAPACITY when the first element is added.
+     */
+    // Android-note: Also accessed from java.util.Collections
+    transient Object[] elementData; // non-private to simplify nested class access
+
+    /**
+     * The size of the ArrayList (the number of elements it contains).
+     *
+     * @serial
+     */
+    private int size;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public ArrayList(int initialCapacity) {
+        if (initialCapacity > 0) {
+            this.elementData = new Object[initialCapacity];
+        } else if (initialCapacity == 0) {
+            this.elementData = EMPTY_ELEMENTDATA;
+        } else {
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        }
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of ten.
+     */
+    public ArrayList() {
+        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayList(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        if ((size = a.length) != 0) {
+            if (c.getClass() == ArrayList.class) {
+                elementData = a;
+            } else {
+                elementData = Arrays.copyOf(a, size, Object[].class);
+            }
+        } else {
+            // replace with empty array.
+            elementData = EMPTY_ELEMENTDATA;
+        }
+    }
+
+    /**
+     * Trims the capacity of this {@code ArrayList} instance to be the
+     * list's current size.  An application can use this operation to minimize
+     * the storage of an {@code ArrayList} instance.
+     */
+    public void trimToSize() {
+        modCount++;
+        if (size < elementData.length) {
+            elementData = (size == 0)
+              ? EMPTY_ELEMENTDATA
+              : Arrays.copyOf(elementData, size);
+        }
+    }
+
+    /**
+     * Increases the capacity of this {@code ArrayList} instance, if
+     * necessary, to ensure that it can hold at least the number of elements
+     * specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    public void ensureCapacity(int minCapacity) {
+        if (minCapacity > elementData.length
+            && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
+                 && minCapacity <= DEFAULT_CAPACITY)) {
+            modCount++;
+            grow(minCapacity);
+        }
+    }
+
+    /**
+     * Increases the capacity to ensure that it can hold at least the
+     * number of elements specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     * @throws OutOfMemoryError if minCapacity is less than zero
+     */
+    private Object[] grow(int minCapacity) {
+        int oldCapacity = elementData.length;
+        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+            int newCapacity = ArraysSupport.newLength(oldCapacity,
+                    minCapacity - oldCapacity, /* minimum growth */
+                    oldCapacity >> 1           /* preferred growth */);
+            return elementData = Arrays.copyOf(elementData, newCapacity);
+        } else {
+            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
+        }
+    }
+
+    private Object[] grow() {
+        return grow(size + 1);
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     */
+    public int indexOf(Object o) {
+        return indexOfRange(o, 0, size);
+    }
+
+    int indexOfRange(Object o, int start, int end) {
+        Object[] es = elementData;
+        if (o == null) {
+            for (int i = start; i < end; i++) {
+                if (es[i] == null) {
+                    return i;
+                }
+            }
+        } else {
+            for (int i = start; i < end; i++) {
+                if (o.equals(es[i])) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     */
+    public int lastIndexOf(Object o) {
+        return lastIndexOfRange(o, 0, size);
+    }
+
+    int lastIndexOfRange(Object o, int start, int end) {
+        Object[] es = elementData;
+        if (o == null) {
+            for (int i = end - 1; i >= start; i--) {
+                if (es[i] == null) {
+                    return i;
+                }
+            }
+        } else {
+            for (int i = end - 1; i >= start; i--) {
+                if (o.equals(es[i])) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ArrayList} instance.  (The
+     * elements themselves are not copied.)
+     *
+     * @return a clone of this {@code ArrayList} instance
+     */
+    public Object clone() {
+        try {
+            ArrayList<?> v = (ArrayList<?>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, size);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in
+     *         proper sequence
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(elementData, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element); the runtime type of the returned
+     * array is that of the specified array.  If the list fits in the
+     * specified array, it is returned therein.  Otherwise, a new array is
+     * allocated with the runtime type of the specified array and the size of
+     * this list.
+     *
+     * <p>If the list fits in the specified array with room to spare
+     * (i.e., the array has more elements than the list), the element in
+     * the array immediately following the end of the collection is set to
+     * {@code null}.  (This is useful in determining the length of the
+     * list <i>only</i> if the caller knows that the list does not contain
+     * any null elements.)
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
+        System.arraycopy(elementData, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    E elementData(int index) {
+        return (E) elementData[index];
+    }
+
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param  index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        Objects.checkIndex(index, size);
+        return elementData(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getFirst() {
+        if (size == 0) {
+            throw new NoSuchElementException();
+        } else {
+            return elementData(0);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getLast() {
+        int last = size - 1;
+        if (last < 0) {
+            throw new NoSuchElementException();
+        } else {
+            return elementData(last);
+        }
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with
+     * the specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        Objects.checkIndex(index, size);
+        E oldValue = elementData(index);
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * This helper method split out from add(E) to keep method
+     * bytecode size under 35 (the -XX:MaxInlineSize default value),
+     * which helps when add(E) is called in a C1-compiled loop.
+     */
+    private void add(E e, Object[] elementData, int s) {
+        if (s == elementData.length)
+            elementData = grow();
+        elementData[s] = e;
+        size = s + 1;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        modCount++;
+        add(e, elementData, size);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        rangeCheckForAdd(index);
+        modCount++;
+        final int s;
+        Object[] elementData;
+        if ((s = size) == (elementData = this.elementData).length)
+            elementData = grow();
+        System.arraycopy(elementData, index,
+                         elementData, index + 1,
+                         s - index);
+        elementData[index] = element;
+        size = s + 1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 21
+     */
+    public void addFirst(E element) {
+        add(0, element);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 21
+     */
+    public void addLast(E element) {
+        add(element);
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).
+     *
+     * @param index the index of the element to be removed
+     * @return the element that was removed from the list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        Objects.checkIndex(index, size);
+        final Object[] es = elementData;
+
+        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
+        fastRemove(es, index);
+
+        return oldValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeFirst() {
+        if (size == 0) {
+            throw new NoSuchElementException();
+        } else {
+            Object[] es = elementData;
+            @SuppressWarnings("unchecked") E oldValue = (E) es[0];
+            fastRemove(es, 0);
+            return oldValue;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeLast() {
+        int last = size - 1;
+        if (last < 0) {
+            throw new NoSuchElementException();
+        } else {
+            Object[] es = elementData;
+            @SuppressWarnings("unchecked") E oldValue = (E) es[last];
+            fastRemove(es, last);
+            return oldValue;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof List)) {
+            return false;
+        }
+
+        final int expectedModCount = modCount;
+        // ArrayList can be subclassed and given arbitrary behavior, but we can
+        // still deal with the common case where o is ArrayList precisely
+        boolean equal = (o.getClass() == ArrayList.class)
+            ? equalsArrayList((ArrayList<?>) o)
+            : equalsRange((List<?>) o, 0, size);
+
+        checkForComodification(expectedModCount);
+        return equal;
+    }
+
+    boolean equalsRange(List<?> other, int from, int to) {
+        final Object[] es = elementData;
+        if (to > es.length) {
+            throw new ConcurrentModificationException();
+        }
+        var oit = other.iterator();
+        for (; from < to; from++) {
+            if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
+                return false;
+            }
+        }
+        return !oit.hasNext();
+    }
+
+    private boolean equalsArrayList(ArrayList<?> other) {
+        final int otherModCount = other.modCount;
+        final int s = size;
+        boolean equal;
+        if (equal = (s == other.size)) {
+            final Object[] otherEs = other.elementData;
+            final Object[] es = elementData;
+            if (s > es.length || s > otherEs.length) {
+                throw new ConcurrentModificationException();
+            }
+            for (int i = 0; i < s; i++) {
+                if (!Objects.equals(es[i], otherEs[i])) {
+                    equal = false;
+                    break;
+                }
+            }
+        }
+        other.checkForComodification(otherModCount);
+        return equal;
+    }
+
+    private void checkForComodification(final int expectedModCount) {
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int expectedModCount = modCount;
+        int hash = hashCodeRange(0, size);
+        checkForComodification(expectedModCount);
+        return hash;
+    }
+
+    int hashCodeRange(int from, int to) {
+        final Object[] es = elementData;
+        if (to > es.length) {
+            throw new ConcurrentModificationException();
+        }
+        int hashCode = 1;
+        for (int i = from; i < to; i++) {
+            Object e = es[i];
+            hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
+        }
+        return hashCode;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If the list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        final Object[] es = elementData;
+        final int size = this.size;
+        int i = 0;
+        found: {
+            if (o == null) {
+                for (; i < size; i++)
+                    if (es[i] == null)
+                        break found;
+            } else {
+                for (; i < size; i++)
+                    if (o.equals(es[i]))
+                        break found;
+            }
+            return false;
+        }
+        fastRemove(es, i);
+        return true;
+    }
+
+    /**
+     * Private remove method that skips bounds checking and does not
+     * return the value removed.
+     */
+    private void fastRemove(Object[] es, int i) {
+        modCount++;
+        final int newSize;
+        if ((newSize = size - 1) > i)
+            System.arraycopy(es, i + 1, es, i, newSize - i);
+        es[size = newSize] = null;
+    }
+
+    /**
+     * Removes all of the elements from this list.  The list will
+     * be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        final Object[] es = elementData;
+        for (int to = size, i = size = 0; i < to; i++)
+            es[i] = null;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's Iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the operation
+     * is in progress.  (This implies that the behavior of this call is
+     * undefined if the specified collection is this list, and this
+     * list is nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        modCount++;
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+        Object[] elementData;
+        final int s;
+        if (numNew > (elementData = this.elementData).length - (s = size))
+            elementData = grow(s + numNew);
+        System.arraycopy(a, 0, elementData, s, numNew);
+        size = s + numNew;
+        return true;
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        rangeCheckForAdd(index);
+
+        Object[] a = c.toArray();
+        modCount++;
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+        Object[] elementData;
+        final int s;
+        if (numNew > (elementData = this.elementData).length - (s = size))
+            elementData = grow(s + numNew);
+
+        int numMoved = s - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index,
+                             elementData, index + numNew,
+                             numMoved);
+        System.arraycopy(a, 0, elementData, index, numNew);
+        size = s + numNew;
+        return true;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @throws IndexOutOfBoundsException if {@code fromIndex} or
+     *         {@code toIndex} is out of range
+     *         ({@code fromIndex < 0 ||
+     *          toIndex > size() ||
+     *          toIndex < fromIndex})
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        if (fromIndex > toIndex) {
+            throw new IndexOutOfBoundsException(
+                    outOfBoundsMsg(fromIndex, toIndex));
+        }
+        modCount++;
+        shiftTailOverGap(elementData, fromIndex, toIndex);
+    }
+
+    /** Erases the gap from lo to hi, by sliding down following elements. */
+    private void shiftTailOverGap(Object[] es, int lo, int hi) {
+        System.arraycopy(es, hi, es, lo, size - hi);
+        for (int to = size, i = (size -= hi - lo); i < to; i++)
+            es[i] = null;
+    }
+
+    /**
+     * A version of rangeCheck used by add and addAll.
+     */
+    private void rangeCheckForAdd(int index) {
+        if (index > size || index < 0)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    /**
+     * Constructs an IndexOutOfBoundsException detail message.
+     * Of the many possible refactorings of the error handling code,
+     * this "outlining" performs best with both server and client VMs.
+     */
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size;
+    }
+
+    /**
+     * A version used in checking (fromIndex > toIndex) condition
+     */
+    private static String outOfBoundsMsg(int fromIndex, int toIndex) {
+        return "From Index: " + fromIndex + " > To Index: " + toIndex;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        return batchRemove(c, false, 0, size);
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all
+     * of its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        return batchRemove(c, true, 0, size);
+    }
+
+    boolean batchRemove(Collection<?> c, boolean complement,
+                        final int from, final int end) {
+        Objects.requireNonNull(c);
+        final Object[] es = elementData;
+        int r;
+        // Optimize for initial run of survivors
+        for (r = from;; r++) {
+            if (r == end)
+                return false;
+            if (c.contains(es[r]) != complement)
+                break;
+        }
+        int w = r++;
+        try {
+            for (Object e; r < end; r++)
+                if (c.contains(e = es[r]) == complement)
+                    es[w++] = e;
+        } catch (Throwable ex) {
+            // Preserve behavioral compatibility with AbstractCollection,
+            // even if c.contains() throws.
+            System.arraycopy(es, r, es, w, end - r);
+            w += end - r;
+            throw ex;
+        } finally {
+            modCount += end - w;
+            shiftTailOverGap(es, w, end);
+        }
+        return true;
+    }
+
+    /**
+     * Saves the state of the {@code ArrayList} instance to a stream
+     * (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The length of the array backing the {@code ArrayList}
+     *             instance is emitted (int), followed by all of its elements
+     *             (each an {@code Object}) in the proper order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out element count, and any hidden stuff
+        int expectedModCount = modCount;
+        s.defaultWriteObject();
+
+        // Write out size as capacity for behavioral compatibility with clone()
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            s.writeObject(elementData[i]);
+        }
+
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Reconstitutes the {@code ArrayList} instance from a stream (that is,
+     * deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in capacity
+        s.readInt(); // ignored
+
+        if (size > 0) {
+            // like clone(), allocate array based upon size not capacity
+            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
+            Object[] elements = new Object[size];
+
+            // Read in all elements in the proper order.
+            for (int i = 0; i < size; i++) {
+                elements[i] = s.readObject();
+            }
+
+            elementData = elements;
+        } else if (size == 0) {
+            elementData = EMPTY_ELEMENTDATA;
+        } else {
+            throw new java.io.InvalidObjectException("Invalid size: " + size);
+        }
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        rangeCheckForAdd(index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-changed: Add "limit" field to detect end of iteration.
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = ArrayList.this.size;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        // prevent creating a synthetic constructor
+        Itr() {}
+
+        public boolean hasNext() {
+            return cursor < limit;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            checkForComodification();
+            int i = cursor;
+            if (i >= limit)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i + 1;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                ArrayList.this.remove(lastRet);
+                cursor = lastRet;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit--;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int size = ArrayList.this.size;
+            int i = cursor;
+            if (i < size) {
+                final Object[] es = elementData;
+                if (i >= es.length)
+                    throw new ConcurrentModificationException();
+                for (; i < size && modCount == expectedModCount; i++)
+                    action.accept(elementAt(es, i));
+                // update once at end to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            checkForComodification();
+            int i = cursor - 1;
+            if (i < 0)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                ArrayList.this.set(lastRet, e);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            checkForComodification();
+
+            try {
+                int i = cursor;
+                ArrayList.this.add(i, e);
+                cursor = i + 1;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit++;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for {@link #indexOf(Object)} and
+     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
+     * {@link Collections} class can be applied to a subList.
+     *
+     * <p>The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size);
+        return new SubList<>(this, fromIndex, toIndex);
+    }
+
+    private static class SubList<E> extends AbstractList<E> implements RandomAccess {
+        private final ArrayList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        private int size;
+
+        /**
+         * Constructs a sublist of an arbitrary ArrayList.
+         */
+        public SubList(ArrayList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        private SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = parent.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E oldValue = root.elementData(offset + index);
+            root.elementData[offset + index] = element;
+            return oldValue;
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.elementData(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(this.size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            root.replaceAllRange(operator, offset, offset + size);
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            return batchRemove(c, false);
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            return batchRemove(c, true);
+        }
+
+        private boolean batchRemove(Collection<?> c, boolean complement) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified =
+                root.batchRemove(c, complement, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified = root.removeIf(filter, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
+        public Object[] toArray() {
+            checkForComodification();
+            return Arrays.copyOfRange(root.elementData, offset, offset + size);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            checkForComodification();
+            if (a.length < size)
+                return (T[]) Arrays.copyOfRange(
+                        root.elementData, offset, offset + size, a.getClass());
+            System.arraycopy(root.elementData, offset, a, 0, size);
+            if (a.length > size)
+                a[size] = null;
+            return a;
+        }
+
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+
+            if (!(o instanceof List)) {
+                return false;
+            }
+
+            boolean equal = root.equalsRange((List<?>)o, offset, offset + size);
+            checkForComodification();
+            return equal;
+        }
+
+        public int hashCode() {
+            int hash = root.hashCodeRange(offset, offset + size);
+            checkForComodification();
+            return hash;
+        }
+
+        public int indexOf(Object o) {
+            int index = root.indexOfRange(o, offset, offset + size);
+            checkForComodification();
+            return index >= 0 ? index - offset : -1;
+        }
+
+        public int lastIndexOf(Object o) {
+            int index = root.lastIndexOfRange(o, offset, offset + size);
+            checkForComodification();
+            return index >= 0 ? index - offset : -1;
+        }
+
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                int cursor = index;
+                int lastRet = -1;
+                int expectedModCount = SubList.this.modCount;
+
+                public boolean hasNext() {
+                    return cursor != SubList.this.size;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E next() {
+                    checkForComodification();
+                    int i = cursor;
+                    if (i >= SubList.this.size)
+                        throw new NoSuchElementException();
+                    Object[] elementData = root.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i + 1;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                public boolean hasPrevious() {
+                    return cursor != 0;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E previous() {
+                    checkForComodification();
+                    int i = cursor - 1;
+                    if (i < 0)
+                        throw new NoSuchElementException();
+                    Object[] elementData = root.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                public void forEachRemaining(Consumer<? super E> action) {
+                    Objects.requireNonNull(action);
+                    final int size = SubList.this.size;
+                    int i = cursor;
+                    if (i < size) {
+                        final Object[] es = root.elementData;
+                        if (offset + i >= es.length)
+                            throw new ConcurrentModificationException();
+                        for (; i < size && root.modCount == expectedModCount; i++)
+                            action.accept(elementAt(es, offset + i));
+                        // update once at end to reduce heap write traffic
+                        cursor = i;
+                        lastRet = i - 1;
+                        checkForComodification();
+                    }
+                }
+
+                public int nextIndex() {
+                    return cursor;
+                }
+
+                public int previousIndex() {
+                    return cursor - 1;
+                }
+
+                public void remove() {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    checkForComodification();
+
+                    try {
+                        SubList.this.remove(lastRet);
+                        cursor = lastRet;
+                        lastRet = -1;
+                        expectedModCount = SubList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void set(E e) {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    checkForComodification();
+
+                    try {
+                        root.set(offset + lastRet, e);
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void add(E e) {
+                    checkForComodification();
+
+                    try {
+                        int i = cursor;
+                        SubList.this.add(i, e);
+                        cursor = i + 1;
+                        lastRet = -1;
+                        expectedModCount = SubList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                final void checkForComodification() {
+                    if (root.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+this.size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
+
+        public Spliterator<E> spliterator() {
+            checkForComodification();
+
+            // This Spliterator needs to late-bind to the subList, not the outer
+            // ArrayList. Note that it is legal for structural changes to be made
+            // to a subList after spliterator() is called but before any spliterator
+            // operations that would causing binding are performed.
+            return new Spliterator<E>() {
+                private int index = offset; // current index, modified on advance/split
+                private int fence = -1; // -1 until used; then one past last index
+                private int expectedModCount; // initialized when fence set
+
+                private int getFence() { // initialize fence to size on first use
+                    int hi; // (a specialized variant appears in method forEach)
+                    if ((hi = fence) < 0) {
+                        expectedModCount = modCount;
+                        hi = fence = offset + size;
+                    }
+                    return hi;
+                }
+
+                public ArrayList<E>.ArrayListSpliterator trySplit() {
+                    int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+                    // ArrayListSpliterator can be used here as the source is already bound
+                    return (lo >= mid) ? null : // divide range in half unless too small
+                        root.new ArrayListSpliterator(lo, index = mid, expectedModCount);
+                }
+
+                public boolean tryAdvance(Consumer<? super E> action) {
+                    Objects.requireNonNull(action);
+                    int hi = getFence(), i = index;
+                    if (i < hi) {
+                        index = i + 1;
+                        @SuppressWarnings("unchecked") E e = (E)root.elementData[i];
+                        action.accept(e);
+                        if (root.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                    return false;
+                }
+
+                public void forEachRemaining(Consumer<? super E> action) {
+                    Objects.requireNonNull(action);
+                    int i, hi, mc; // hoist accesses and checks from loop
+                    ArrayList<E> lst = root;
+                    Object[] a;
+                    if ((a = lst.elementData) != null) {
+                        if ((hi = fence) < 0) {
+                            mc = modCount;
+                            hi = offset + size;
+                        }
+                        else
+                            mc = expectedModCount;
+                        if ((i = index) >= 0 && (index = hi) <= a.length) {
+                            for (; i < hi; ++i) {
+                                @SuppressWarnings("unchecked") E e = (E) a[i];
+                                action.accept(e);
+                            }
+                            if (lst.modCount == mc)
+                                return;
+                        }
+                    }
+                    throw new ConcurrentModificationException();
+                }
+
+                public long estimateSize() {
+                    return getFence() - index;
+                }
+
+                public int characteristics() {
+                    return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+                }
+            };
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int size = this.size;
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new ArrayListSpliterator(0, -1, 0);
+    }
+
+    /** Index-based split-by-two, lazily initialized Spliterator */
+    final class ArrayListSpliterator implements Spliterator<E> {
+
+        /*
+         * If ArrayLists were immutable, or structurally immutable (no
+         * adds, removes, etc), we could implement their spliterators
+         * with Arrays.spliterator. Instead we detect as much
+         * interference during traversal as practical without
+         * sacrificing much performance. We rely primarily on
+         * modCounts. These are not guaranteed to detect concurrency
+         * violations, and are sometimes overly conservative about
+         * within-thread interference, but detect enough problems to
+         * be worthwhile in practice. To carry this out, we (1) lazily
+         * initialize fence and expectedModCount until the latest
+         * point that we need to commit to the state we are checking
+         * against; thus improving precision. (2) We perform only a single
+         * ConcurrentModificationException check at the end of forEach
+         * (the most performance-sensitive method). When using forEach
+         * (as opposed to iterators), we can normally only detect
+         * interference after actions, not before. Further
+         * CME-triggering checks apply to all other possible
+         * violations of assumptions for example null or too-small
+         * elementData array given its size(), that could only have
+         * occurred due to interference.  This allows the inner loop
+         * of forEach to run without any further checks, and
+         * simplifies lambda-resolution. While this does entail a
+         * number of checks, note that in the common case of
+         * list.stream().forEach(a), no checks or other computation
+         * occur anywhere other than inside forEach itself.  The other
+         * less-often-used methods cannot take advantage of most of
+         * these streamlinings.
+         */
+
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Creates new spliterator covering the given range. */
+        ArrayListSpliterator(int origin, int fence, int expectedModCount) {
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi; // (a specialized variant appears in method forEach)
+            if ((hi = fence) < 0) {
+                expectedModCount = modCount;
+                hi = fence = size;
+            }
+            return hi;
+        }
+
+        public ArrayListSpliterator trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                new ArrayListSpliterator(lo, index = mid, expectedModCount);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                @SuppressWarnings("unchecked") E e = (E)elementData[i];
+                action.accept(e);
+                if (modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi, mc; // hoist accesses and checks from loop
+            Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = elementData) != null) {
+                if ((hi = fence) < 0) {
+                    mc = modCount;
+                    hi = size;
+                }
+                else
+                    mc = expectedModCount;
+                if ((i = index) >= 0 && (index = hi) <= a.length) {
+                    for (; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) a[i];
+                        action.accept(e);
+                    }
+                    if (modCount == mc)
+                        return;
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return getFence() - index;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        return removeIf(filter, 0, size);
+    }
+
+    /**
+     * Removes all elements satisfying the given predicate, from index
+     * i (inclusive) to index end (exclusive).
+     */
+    boolean removeIf(Predicate<? super E> filter, int i, final int end) {
+        Objects.requireNonNull(filter);
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            shiftTailOverGap(es, w, end);
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
+    }
+
+    @Override
+    public void replaceAll(UnaryOperator<E> operator) {
+        replaceAllRange(operator, 0, size);
+        // TODO(8203662): remove increment of modCount from ...
+        modCount++;
+    }
+
+    private void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final Object[] es = elementData;
+        for (; modCount == expectedModCount && i < end; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, size, c);
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+        modCount++;
+    }
+
+    void checkInvariants() {
+        // assert size >= 0;
+        // assert size == elementData.length || elementData[size] == null;
+    }
+}
diff --git a/android-35/java/util/ArrayPrefixHelpers.java b/android-35/java/util/ArrayPrefixHelpers.java
new file mode 100644
index 0000000..303c779
--- /dev/null
+++ b/android-35/java/util/ArrayPrefixHelpers.java
@@ -0,0 +1,718 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * ForkJoin tasks to perform Arrays.parallelPrefix operations.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+class ArrayPrefixHelpers {
+    private ArrayPrefixHelpers() {} // non-instantiable
+
+    /*
+     * Parallel prefix (aka cumulate, scan) task classes
+     * are based loosely on Guy Blelloch's original
+     * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html):
+     *  Keep dividing by two to threshold segment size, and then:
+     *   Pass 1: Create tree of partial sums for each segment
+     *   Pass 2: For each segment, cumulate with offset of left sibling
+     *
+     * This version improves performance within FJ framework mainly by
+     * allowing the second pass of ready left-hand sides to proceed
+     * even if some right-hand side first passes are still executing.
+     * It also combines first and second pass for leftmost segment,
+     * and skips the first pass for rightmost segment (whose result is
+     * not needed for second pass).  It similarly manages to avoid
+     * requiring that users supply an identity basis for accumulations
+     * by tracking those segments/subtasks for which the first
+     * existing element is used as base.
+     *
+     * Managing this relies on ORing some bits in the pendingCount for
+     * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the
+     * main phase bit. When false, segments compute only their sum.
+     * When true, they cumulate array elements. CUMULATE is set at
+     * root at beginning of second pass and then propagated down. But
+     * it may also be set earlier for subtrees with lo==0 (the left
+     * spine of tree). SUMMED is a one bit join count. For leafs, it
+     * is set when summed. For internal nodes, it becomes true when
+     * one child is summed.  When the second child finishes summing,
+     * we then moves up tree to trigger the cumulate phase. FINISHED
+     * is also a one bit join count. For leafs, it is set when
+     * cumulated. For internal nodes, it becomes true when one child
+     * is cumulated.  When the second child finishes cumulating, it
+     * then moves up tree, completing at the root.
+     *
+     * To better exploit locality and reduce overhead, the compute
+     * method loops starting with the current task, moving if possible
+     * to one of its subtasks rather than forking.
+     *
+     * As usual for this sort of utility, there are 4 versions, that
+     * are simple copy/paste/adapt variants of each other.  (The
+     * double and int versions differ from long version solely by
+     * replacing "long" (with case-matching)).
+     */
+
+    // see above
+    static final int CUMULATE = 1;
+    static final int SUMMED   = 2;
+    static final int FINISHED = 4;
+
+    /** The smallest subtask array partition size to use as threshold */
+    static final int MIN_PARTITION = 16;
+
+    static final class CumulateTask<T> extends CountedCompleter<Void> {
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        final T[] array;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        final BinaryOperator<T> function;
+        CumulateTask<T> left, right;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        T in;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        T out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public CumulateTask(CumulateTask<T> parent,
+                            BinaryOperator<T> function,
+                            T[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function,
+                     T[] array, int origin, int fence, int threshold,
+                     int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final BinaryOperator<T> fn;
+            final T[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            CumulateTask<T> t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    CumulateTask<T> lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        T pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            T lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.apply(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    T sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.apply(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.apply(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (CumulateTask<T> par;;) {             // propagate
+                        @SuppressWarnings("unchecked") CumulateTask<T> partmp
+                            = (CumulateTask<T>)t.getCompleter();
+                        if ((par = partmp) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; CumulateTask<T> lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                T lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.apply(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        @java.io.Serial
+        private static final long serialVersionUID = 5293554502939613543L;
+    }
+
+    static final class LongCumulateTask extends CountedCompleter<Void> {
+        final long[] array;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        final LongBinaryOperator function;
+        LongCumulateTask left, right;
+        long in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public LongCumulateTask(LongCumulateTask parent,
+                                LongBinaryOperator function,
+                                long[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function,
+                         long[] array, int origin, int fence, int threshold,
+                         int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final LongBinaryOperator fn;
+            final long[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            LongCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    LongCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        long pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            long lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsLong(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    long sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (LongCumulateTask par;;) {            // propagate
+                        if ((par = (LongCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; LongCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                long lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsLong(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        @java.io.Serial
+        private static final long serialVersionUID = -5074099945909284273L;
+    }
+
+    static final class DoubleCumulateTask extends CountedCompleter<Void> {
+        final double[] array;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        final DoubleBinaryOperator function;
+        DoubleCumulateTask left, right;
+        double in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public DoubleCumulateTask(DoubleCumulateTask parent,
+                                  DoubleBinaryOperator function,
+                                  double[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function,
+                           double[] array, int origin, int fence, int threshold,
+                           int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final DoubleBinaryOperator fn;
+            final double[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            DoubleCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    DoubleCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        double pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            double lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsDouble(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    double sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (DoubleCumulateTask par;;) {            // propagate
+                        if ((par = (DoubleCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; DoubleCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                double lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsDouble(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        @java.io.Serial
+        private static final long serialVersionUID = -586947823794232033L;
+    }
+
+    static final class IntCumulateTask extends CountedCompleter<Void> {
+        final int[] array;
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        final IntBinaryOperator function;
+        IntCumulateTask left, right;
+        int in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public IntCumulateTask(IntCumulateTask parent,
+                               IntBinaryOperator function,
+                               int[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function,
+                        int[] array, int origin, int fence, int threshold,
+                        int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final IntBinaryOperator fn;
+            final int[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            IntCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    IntCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        int pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            int lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsInt(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    int sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (IntCumulateTask par;;) {            // propagate
+                        if ((par = (IntCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; IntCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                int lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsInt(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        @java.io.Serial
+        private static final long serialVersionUID = 3731755594596840961L;
+    }
+}
diff --git a/android-35/java/util/Arrays.java b/android-35/java/util/Arrays.java
new file mode 100644
index 0000000..995dec8
--- /dev/null
+++ b/android-35/java/util/Arrays.java
@@ -0,0 +1,8800 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+
+import jdk.internal.util.ArraysSupport;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.UnaryOperator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class contains various methods for manipulating arrays (such as
+ * sorting and searching). This class also contains a static factory
+ * that allows arrays to be viewed as lists.
+ *
+ * <p>The methods in this class all throw a {@code NullPointerException},
+ * if the specified array reference is null, except where noted.
+ *
+ * <p>The documentation for the methods contained in this class includes
+ * brief descriptions of the <i>implementations</i>. Such descriptions should
+ * be regarded as <i>implementation notes</i>, rather than parts of the
+ * <i>specification</i>. Implementors should feel free to substitute other
+ * algorithms, so long as the specification itself is adhered to. (For
+ * example, the algorithm used by {@code sort(Object[])} does not have to be
+ * a MergeSort, but it does have to be <i>stable</i>.)
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @author Neal Gafter
+ * @author John Rose
+ * @since  1.2
+ */
+public class Arrays {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Arrays() {}
+
+    /*
+     * Sorting methods. Note that all public "sort" methods take the
+     * same form: performing argument checks if necessary, and then
+     * expanding arguments into those required for the internal
+     * implementation methods residing in other package-private
+     * classes (except for legacyMergeSort, included in this class).
+     */
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(int[] a) {
+        DualPivotQuicksort.sort(a, 0, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, 0, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(long[] a) {
+        DualPivotQuicksort.sort(a, 0, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, 0, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(short[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(char[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(byte[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(float[] a) {
+        DualPivotQuicksort.sort(a, 0, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, 0, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(double[] a) {
+        DualPivotQuicksort.sort(a, 0, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, 0, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a) {
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a) {
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a) {
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a) {
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+     * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+     * offers O(n log(n)) performance on all data sets, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex);
+    }
+
+    /**
+     * Checks that {@code fromIndex} and {@code toIndex} are in
+     * the range and throws an exception if they aren't.
+     */
+    static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException(
+                "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex < 0) {
+            throw new ArrayIndexOutOfBoundsException(fromIndex);
+        }
+        if (toIndex > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(toIndex);
+        }
+    }
+
+    /**
+     * A comparator that implements the natural ordering of a group of
+     * mutually comparable elements. May be used when a supplied
+     * comparator is null. To simplify code-sharing within underlying
+     * implementations, the compare method only declares type Object
+     * for its second argument.
+     *
+     * Arrays class implementor's note: It is an empirical matter
+     * whether ComparableTimSort offers any performance benefit over
+     * TimSort used with this comparator.  If not, you are better off
+     * deleting or bypassing ComparableTimSort.  There is currently no
+     * empirical case for separating them for parallel sorting, so all
+     * public Object parallelSort methods use the same comparator
+     * based implementation.
+     */
+    static final class NaturalOrder implements Comparator<Object> {
+        @SuppressWarnings("unchecked")
+        public int compare(Object first, Object second) {
+            return ((Comparable<Object>)first).compareTo(second);
+        }
+        static final NaturalOrder INSTANCE = new NaturalOrder();
+    }
+
+    /**
+     * The minimum array length below which a parallel sorting
+     * algorithm will not further partition the sorting task. Using
+     * smaller sizes typically results in memory contention across
+     * tasks that makes parallel speedups unlikely.
+     *
+     * @hide
+     */
+    // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony
+    // ArraysTest).
+    public static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     *
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>>
+    void parallelSort(T[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link java.util.Comparator} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
+                                        Comparator<? super T> cmp) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /*
+     * Sorting of complex type arrays.
+     */
+
+    // BEGIN Android-removed: LegacyMergeSort class (unused on Android).
+    /*
+    /**
+     * Old merge sort implementation can be selected (for
+     * compatibility with broken comparators) using a system property.
+     * Cannot be a static boolean in the enclosing class due to
+     * circular dependencies. To be removed in a future release.
+     * 
+    static final class LegacyMergeSort {
+        @SuppressWarnings("removal")
+        private static final boolean userRequested =
+            java.security.AccessController.doPrivileged(
+                new sun.security.action.GetBooleanAction(
+                    "java.util.Arrays.useLegacyMergeSort")).booleanValue();
+    }
+    */
+    // END Android-removed: LegacyMergeSort class (unused on Android).
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     */
+    public static void sort(Object[] a) {
+        // BEGIN Android-removed: LegacyMergeSort support.
+        /*
+        if (LegacyMergeSort.userRequested)
+            legacyMergeSort(a);
+        else
+        */
+        // END Android-removed: LegacyMergeSort support.
+            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
+    }
+
+    // BEGIN Android-removed: legacyMergeSort() (unused on Android).
+    /*
+    /** To be removed in a future release.
+    private static void legacyMergeSort(Object[] a) {
+        Object[] aux = a.clone();
+        mergeSort(aux, a, 0, a.length, 0);
+    }
+    */
+    // END Android-removed: legacyMergeSort() (unused on Android).
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     */
+    public static void sort(Object[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        // BEGIN Android-removed: LegacyMergeSort support.
+        /*
+        if (LegacyMergeSort.userRequested)
+            legacyMergeSort(a, fromIndex, toIndex);
+        else
+        */
+        // END Android-removed: LegacyMergeSort support.
+            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
+    }
+
+    // BEGIN Android-removed: legacyMergeSort() (unused on Android).
+    /*
+    /** To be removed in a future release. *
+    private static void legacyMergeSort(Object[] a,
+                                        int fromIndex, int toIndex) {
+        Object[] aux = copyOfRange(a, fromIndex, toIndex);
+        mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
+    }
+    */
+    // END Android-removed: legacyMergeSort() (unused on Android).
+
+
+    /**
+     * Tuning parameter: list size at or below which insertion sort will be
+     * used in preference to mergesort.
+     * To be removed in a future release.
+     */
+    private static final int INSERTIONSORT_THRESHOLD = 7;
+
+    /**
+     * Src is the source array that starts at index 0
+     * Dest is the (possibly larger) array destination with a possible offset
+     * low is the index in dest to start sorting
+     * high is the end index in dest to end sorting
+     * off is the offset to generate corresponding low, high in src
+     * To be removed in a future release.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static void mergeSort(Object[] src,
+                                  Object[] dest,
+                                  int low,
+                                  int high,
+                                  int off) {
+        int length = high - low;
+
+        // Insertion sort on smallest arrays
+        if (length < INSERTIONSORT_THRESHOLD) {
+            for (int i=low; i<high; i++)
+                for (int j=i; j>low &&
+                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
+                    swap(dest, j, j-1);
+            return;
+        }
+
+        // Recursively sort halves of dest into src
+        int destLow  = low;
+        int destHigh = high;
+        low  += off;
+        high += off;
+        int mid = (low + high) >>> 1;
+        mergeSort(dest, src, low, mid, -off);
+        mergeSort(dest, src, mid, high, -off);
+
+        // If list is already sorted, just copy from src to dest.  This is an
+        // optimization that results in faster sorts for nearly ordered lists.
+        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
+            System.arraycopy(src, low, dest, destLow, length);
+            return;
+        }
+
+        // Merge sorted halves (now in src) into dest
+        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
+            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
+                dest[i] = src[p++];
+            else
+                dest[i] = src[q++];
+        }
+    }
+
+    /**
+     * Swaps x[a] with x[b].
+     */
+    private static void swap(Object[] x, int a, int b) {
+        Object t = x[a];
+        x[a] = x[b];
+        x[b] = t;
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     */
+    public static <T> void sort(T[] a, Comparator<? super T> c) {
+        if (c == null) {
+            sort(a);
+        } else {
+            // BEGIN Android-removed: LegacyMergeSort support.
+            /*
+            if (LegacyMergeSort.userRequested)
+                legacyMergeSort(a, c);
+            else
+            */
+            // END Android-removed: LegacyMergeSort support.
+                TimSort.sort(a, 0, a.length, c, null, 0, 0);
+        }
+    }
+
+    // BEGIN Android-removed: legacyMergeSort() (unused on Android).
+    /** To be removed in a future release. *
+    private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) {
+        T[] aux = a.clone();
+        if (c==null)
+            mergeSort(aux, a, 0, a.length, 0);
+        else
+            mergeSort(aux, a, 0, a.length, 0, c);
+    }
+    */
+    // END Android-removed: legacyMergeSort() (unused on Android).
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the comparator is found to violate the
+     *         {@link Comparator} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static <T> void sort(T[] a, int fromIndex, int toIndex,
+                                Comparator<? super T> c) {
+        if (c == null) {
+            sort(a, fromIndex, toIndex);
+        } else {
+            rangeCheck(a.length, fromIndex, toIndex);
+            // BEGIN Android-removed: LegacyMergeSort support.
+            /*
+            if (LegacyMergeSort.userRequested)
+                legacyMergeSort(a, fromIndex, toIndex, c);
+            else
+            */
+            // END Android-removed: LegacyMergeSort support.
+                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
+        }
+    }
+
+    // BEGIN Android-removed: legacyMergeSort() and mergeSort() (unused on Android).
+    /*
+    /** To be removed in a future release. *
+    private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
+                                            Comparator<? super T> c) {
+        T[] aux = copyOfRange(a, fromIndex, toIndex);
+        if (c==null)
+            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
+        else
+            mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
+    }
+
+    /**
+     * Src is the source array that starts at index 0
+     * Dest is the (possibly larger) array destination with a possible offset
+     * low is the index in dest to start sorting
+     * high is the end index in dest to end sorting
+     * off is the offset into src corresponding to low in dest
+     * To be removed in a future release.
+     *
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static void mergeSort(Object[] src,
+                                  Object[] dest,
+                                  int low, int high, int off,
+                                  Comparator c) {
+        int length = high - low;
+
+        // Insertion sort on smallest arrays
+        if (length < INSERTIONSORT_THRESHOLD) {
+            for (int i=low; i<high; i++)
+                for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
+                    swap(dest, j, j-1);
+            return;
+        }
+
+        // Recursively sort halves of dest into src
+        int destLow  = low;
+        int destHigh = high;
+        low  += off;
+        high += off;
+        int mid = (low + high) >>> 1;
+        mergeSort(dest, src, low, mid, -off, c);
+        mergeSort(dest, src, mid, high, -off, c);
+
+        // If list is already sorted, just copy from src to dest.  This is an
+        // optimization that results in faster sorts for nearly ordered lists.
+        if (c.compare(src[mid-1], src[mid]) <= 0) {
+           System.arraycopy(src, low, dest, destLow, length);
+           return;
+        }
+
+        // Merge sorted halves (now in src) into dest
+        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
+            if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
+                dest[i] = src[p++];
+            else
+                dest[i] = src[q++];
+        }
+    }
+    */
+    // END Android-removed: legacyMergeSort() and mergeSort() (unused on Android).
+
+    // Parallel prefix
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(Object[], BinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, int fromIndex,
+                                          int toIndex, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(long[], LongBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, int fromIndex,
+                                      int toIndex, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition,
+     * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * <p> Because floating-point operations may not be strictly associative,
+     * the returned result may not be identical to the value that would be
+     * obtained if the operation was performed sequentially.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free function to perform the cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, int fromIndex,
+                                      int toIndex, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(int[], IntBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, int fromIndex,
+                                      int toIndex, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    // Searching
+
+    /**
+     * Searches the specified array of longs for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(long[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(long[] a, long key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of longs for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(long[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(long[] a, int fromIndex, int toIndex,
+                                   long key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(long[] a, int fromIndex, int toIndex,
+                                     long key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            long midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of ints for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(int[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(int[] a, int key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of ints for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(int[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(int[] a, int fromIndex, int toIndex,
+                                   int key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
+                                     int key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            int midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of shorts for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(short[])} method) prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(short[] a, short key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of shorts for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(short[], int, int)} method)
+     * prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(short[] a, int fromIndex, int toIndex,
+                                   short key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(short[] a, int fromIndex, int toIndex,
+                                     short key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            short midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of chars for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(char[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(char[] a, char key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of chars for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(char[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(char[] a, int fromIndex, int toIndex,
+                                   char key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(char[] a, int fromIndex, int toIndex,
+                                     char key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            char midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of bytes for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(byte[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(byte[] a, byte key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of bytes for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(byte[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(byte[] a, int fromIndex, int toIndex,
+                                   byte key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(byte[] a, int fromIndex, int toIndex,
+                                     byte key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            byte midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of doubles for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(double[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(double[] a, double key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of doubles for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(double[], int, int)} method)
+     * prior to making this call.
+     * If it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(double[] a, int fromIndex, int toIndex,
+                                   double key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(double[] a, int fromIndex, int toIndex,
+                                     double key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            double midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                long midBits = Double.doubleToLongBits(midVal);
+                long keyBits = Double.doubleToLongBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of floats for the specified value using
+     * the binary search algorithm. The array must be sorted
+     * (as by the {@link #sort(float[])} method) prior to making this call. If
+     * it is not sorted, the results are undefined. If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(float[] a, float key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of floats for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(float[], int, int)} method)
+     * prior to making this call. If
+     * it is not sorted, the results are undefined. If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(float[] a, int fromIndex, int toIndex,
+                                   float key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(float[] a, int fromIndex, int toIndex,
+                                     float key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            float midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                int midBits = Float.floatToIntBits(midVal);
+                int keyBits = Float.floatToIntBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm. The array must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * (If the array contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array.
+     */
+    public static int binarySearch(Object[] a, Object key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[], int, int)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.
+     * (If the range contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the range contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array within the specified range.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(Object[] a, int fromIndex, int toIndex,
+                                   Object key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
+                                     Object key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            @SuppressWarnings("rawtypes")
+            Comparable midVal = (Comparable)a[mid];
+            @SuppressWarnings("unchecked")
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm.  The array must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], Comparator) sort(T[], Comparator)}
+     * method) prior to making this call.  If it is
+     * not sorted, the results are undefined.
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or {@code a.length} if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements of the array using this comparator.
+     */
+    public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
+        return binarySearch0(a, 0, a.length, key, c);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], int, int, Comparator)
+     * sort(T[], int, int, Comparator)}
+     * method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * If the range contains multiple elements equal to the specified object,
+     * there is no guarantee which one will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or {@code toIndex} if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the range contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements in the range using this comparator.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
+                                       T key, Comparator<? super T> c) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key, c);
+    }
+
+    // Like public version, but without range checks.
+    private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
+                                         T key, Comparator<? super T> c) {
+        if (c == null) {
+            return binarySearch0(a, fromIndex, toIndex, key);
+        }
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = a[mid];
+            int cmp = c.compare(midVal, key);
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    // Equality Testing
+
+    /**
+     * Returns {@code true} if the two specified arrays of longs are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    public static boolean equals(long[] a, long[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of longs, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(long[] a, int aFromIndex, int aToIndex,
+                                 long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of ints are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    public static boolean equals(int[] a, int[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of ints, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(int[] a, int aFromIndex, int aToIndex,
+                                 int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of shorts are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    public static boolean equals(short[] a, short a2[]) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of shorts, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(short[] a, int aFromIndex, int aToIndex,
+                                 short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of chars are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    @IntrinsicCandidate
+    public static boolean equals(char[] a, char[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of chars, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(char[] a, int aFromIndex, int aToIndex,
+                                 char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of bytes are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    @IntrinsicCandidate
+    public static boolean equals(byte[] a, byte[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of bytes, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(byte[] a, int aFromIndex, int aToIndex,
+                                 byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of booleans are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    public static boolean equals(boolean[] a, boolean[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of booleans, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(boolean[] a, int aFromIndex, int aToIndex,
+                                 boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex,
+                                      aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of doubles are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * Two doubles {@code d1} and {@code d2} are considered equal if:
+     * <pre>    {@code new Double(d1).equals(new Double(d2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equal to itself, and 0.0d unequal to -0.0d.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     * @see Double#equals(Object)
+     */
+    public static boolean equals(double[] a, double[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of doubles, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two doubles {@code d1} and {@code d2} are considered equal if:
+     * <pre>    {@code new Double(d1).equals(new Double(d2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equal to itself, and 0.0d unequal to -0.0d.)
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @see Double#equals(Object)
+     * @since 9
+     */
+    public static boolean equals(double[] a, int aFromIndex, int aToIndex,
+                                 double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex, aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of floats are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are {@code null}.
+     *
+     * Two floats {@code f1} and {@code f2} are considered equal if:
+     * <pre>    {@code new Float(f1).equals(new Float(f2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equal to itself, and 0.0f unequal to -0.0f.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     * @see Float#equals(Object)
+     */
+    public static boolean equals(float[] a, float[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        return ArraysSupport.mismatch(a, a2, length) < 0;
+    }
+
+    /**
+     * Returns true if the two specified arrays of floats, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two floats {@code f1} and {@code f2} are considered equal if:
+     * <pre>    {@code new Float(f1).equals(new Float(f2))}</pre>
+     * (Unlike the {@code ==} operator, this method considers
+     * {@code NaN} equal to itself, and 0.0f unequal to -0.0f.)
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @see Float#equals(Object)
+     * @since 9
+     */
+    public static boolean equals(float[] a, int aFromIndex, int aToIndex,
+                                 float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        return ArraysSupport.mismatch(a, aFromIndex,
+                                      b, bFromIndex, aLength) < 0;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of Objects are
+     * <i>equal</i> to one another.  The two arrays are considered equal if
+     * both arrays contain the same number of elements, and all corresponding
+     * pairs of elements in the two arrays are equal.  Two objects {@code e1}
+     * and {@code e2} are considered <i>equal</i> if
+     * {@code Objects.equals(e1, e2)}.
+     * In other words, the two arrays are equal if
+     * they contain the same elements in the same order.  Also, two array
+     * references are considered equal if both are {@code null}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     */
+    public static boolean equals(Object[] a, Object[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++) {
+            if (!Objects.equals(a[i], a2[i]))
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the two specified arrays of Objects, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if
+     * {@code Objects.equals(e1, e2)}.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static boolean equals(Object[] a, int aFromIndex, int aToIndex,
+                                 Object[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        for (int i = 0; i < aLength; i++) {
+            if (!Objects.equals(a[aFromIndex++], b[bFromIndex++]))
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays of Objects are
+     * <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if both arrays contain the same number
+     * of elements, and all corresponding pairs of elements in the two arrays
+     * are equal.  In other words, the two arrays are equal if they contain the
+     * same elements in the same order.  Also, two array references are
+     * considered equal if both are {@code null}.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+     * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return {@code true} if the two arrays are equal
+     * @throws NullPointerException if the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> boolean equals(T[] a, T[] a2, Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++) {
+            if (cmp.compare(a[i], a2[i]) != 0)
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the two specified arrays of Objects, over the specified
+     * ranges, are <i>equal</i> to one another.
+     *
+     * <p>Two arrays are considered equal if the number of elements covered by
+     * each range is the same, and all corresponding pairs of elements over the
+     * specified ranges in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain, over the specified ranges, the same elements
+     * in the same order.
+     *
+     * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+     * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+     *
+     * @param a the first array to be tested for equality
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for equality
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return {@code true} if the two arrays, over the specified ranges, are
+     *         equal
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> boolean equals(T[] a, int aFromIndex, int aToIndex,
+                                     T[] b, int bFromIndex, int bToIndex,
+                                     Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        if (aLength != bLength)
+            return false;
+
+        for (int i = 0; i < aLength; i++) {
+            if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0)
+                return false;
+        }
+
+        return true;
+    }
+
+    // Filling
+
+    /**
+     * Assigns the specified long value to each element of the specified array
+     * of longs.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(long[] a, long val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified long value to each element of the specified
+     * range of the specified array of longs.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(long[] a, int fromIndex, int toIndex, long val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified array
+     * of ints.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(int[] a, int val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified
+     * range of the specified array of ints.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(int[] a, int fromIndex, int toIndex, int val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified array
+     * of shorts.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(short[] a, short val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified
+     * range of the specified array of shorts.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(short[] a, int fromIndex, int toIndex, short val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified array
+     * of chars.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(char[] a, char val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified
+     * range of the specified array of chars.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(char[] a, int fromIndex, int toIndex, char val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified array
+     * of bytes.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(byte[] a, byte val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified
+     * range of the specified array of bytes.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * array of booleans.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(boolean[] a, boolean val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * range of the specified array of booleans.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(boolean[] a, int fromIndex, int toIndex,
+                            boolean val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * array of doubles.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(double[] a, double val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * range of the specified array of doubles.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(double[] a, int fromIndex, int toIndex,double val){
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified array
+     * of floats.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(float[] a, float val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified
+     * range of the specified array of floats.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static void fill(float[] a, int fromIndex, int toIndex, float val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * array of Objects.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, Object val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * range of the specified array of Objects.  The range to be filled
+     * extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    // Cloning
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code null}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOf(T[] original, int newLength) {
+        return (T[]) copyOf(original, newLength, original.getClass());
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code null}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of the class {@code newType}.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @param newType the class of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @throws ArrayStoreException if an element copied from
+     *     {@code original} is not of a runtime type that can be stored in
+     *     an array of class {@code newType}
+     * @since 1.6
+     */
+    @IntrinsicCandidate
+    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code (byte)0}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static byte[] copyOf(byte[] original, int newLength) {
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code (short)0}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static short[] copyOf(short[] original, int newLength) {
+        short[] copy = new short[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code 0}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static int[] copyOf(int[] original, int newLength) {
+        int[] copy = new int[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code 0L}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static long[] copyOf(long[] original, int newLength) {
+        long[] copy = new long[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with null characters (if necessary)
+     * so the copy has the specified length.  For all indices that are valid
+     * in both the original array and the copy, the two arrays will contain
+     * identical values.  For any indices that are valid in the copy but not
+     * the original, the copy will contain {@code '\u005cu0000'}.  Such indices
+     * will exist if and only if the specified length is greater than that of
+     * the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with null characters
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static char[] copyOf(char[] original, int newLength) {
+        char[] copy = new char[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code 0f}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static float[] copyOf(float[] original, int newLength) {
+        float[] copy = new float[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code 0d}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static double[] copyOf(double[] original, int newLength) {
+        double[] copy = new double[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with {@code false} (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain {@code false}.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with false elements
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if {@code newLength} is negative
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static boolean[] copyOf(boolean[] original, int newLength) {
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code null} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     * <p>
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOfRange(T[] original, int from, int to) {
+        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code null} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     * The resulting array is of the class {@code newType}.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @param newType the class of the copy to be returned
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @throws ArrayStoreException if an element copied from
+     *     {@code original} is not of a runtime type that can be stored in
+     *     an array of class {@code newType}.
+     * @since 1.6
+     */
+    @IntrinsicCandidate
+    public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code (byte)0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static byte[] copyOfRange(byte[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code (short)0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static short[] copyOfRange(short[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        short[] copy = new short[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static int[] copyOfRange(int[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        int[] copy = new int[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0L} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static long[] copyOfRange(long[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        long[] copy = new long[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code '\u005cu0000'} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with null characters to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static char[] copyOfRange(char[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        char[] copy = new char[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0f} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static float[] copyOfRange(float[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        float[] copy = new float[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code 0d} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static double[] copyOfRange(double[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        double[] copy = new double[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range ({@code from}) must lie between zero
+     * and {@code original.length}, inclusive.  The value at
+     * {@code original[from]} is placed into the initial element of the copy
+     * (unless {@code from == original.length} or {@code from == to}).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * ({@code to}), which must be greater than or equal to {@code from},
+     * may be greater than {@code original.length}, in which case
+     * {@code false} is placed in all elements of the copy whose index is
+     * greater than or equal to {@code original.length - from}.  The length
+     * of the returned array will be {@code to - from}.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with false elements to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if {@code from > to}
+     * @throws NullPointerException if {@code original} is null
+     * @since 1.6
+     */
+    public static boolean[] copyOfRange(boolean[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    // Misc
+
+    /**
+     * Returns a fixed-size list backed by the specified array. Changes made to
+     * the array will be visible in the returned list, and changes made to the
+     * list will be visible in the array. The returned list is
+     * {@link Serializable} and implements {@link RandomAccess}.
+     *
+     * <p>The returned list implements the optional {@code Collection} methods, except
+     * those that would change the size of the returned list. Those methods leave
+     * the list unchanged and throw {@link UnsupportedOperationException}.
+     *
+     * @apiNote
+     * This method acts as bridge between array-based and collection-based
+     * APIs, in combination with {@link Collection#toArray}.
+     *
+     * <p>This method provides a way to wrap an existing array:
+     * <pre>{@code
+     *     Integer[] numbers = ...
+     *     ...
+     *     List<Integer> values = Arrays.asList(numbers);
+     * }</pre>
+     *
+     * <p>This method also provides a convenient way to create a fixed-size
+     * list initialized to contain several elements:
+     * <pre>{@code
+     *     List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
+     * }</pre>
+     *
+     * <p><em>The list returned by this method is modifiable.</em>
+     * To create an unmodifiable list, use
+     * {@link Collections#unmodifiableList Collections.unmodifiableList}
+     * or <a href="List.html#unmodifiable">Unmodifiable Lists</a>.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array by which the list will be backed
+     * @return a list view of the specified array
+     * @throws NullPointerException if the specified array is {@code null}
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static <T> List<T> asList(T... a) {
+        return new ArrayList<>(a);
+    }
+
+    /**
+     * Since Android 15 Arrays.asList(...).toArray()'s component type is {@link Object},
+     * not the underlying array's elements type. So the following code will throw
+     * {@link ClassCastException}:
+     * <pre>{@code
+     * String[] elements = (String[]) Arrays.asList("one", "two").toArray();
+     * }</pre>
+     * You can overcome this by using {@link Collection#toArray(Object[])}:
+     * <pre>{@code
+     * String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
+     * }</pre>
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.VANILLA_ICE_CREAM)
+    public static final long DO_NOT_CLONE_IN_ARRAYS_AS_LIST = 202956589L;
+
+    /**
+     * @serial include
+     */
+    private static class ArrayList<E> extends AbstractList<E>
+        implements RandomAccess, java.io.Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -2764017481108945198L;
+        private final E[] a;
+
+        ArrayList(E[] array) {
+            a = Objects.requireNonNull(array);
+        }
+
+        @Override
+        public int size() {
+            return a.length;
+        }
+
+        @Override
+        public Object[] toArray() {
+            // Android-changed: there are applications which expect this method
+            // to return array with component type E, not just Object.
+            // Keeping pre-Java 9 behaviour for compatibility's sake.
+            // See b/204397945.
+            if (VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM
+                    && Compatibility.isChangeEnabled(DO_NOT_CLONE_IN_ARRAYS_AS_LIST)) {
+                return toArrayWithoutComponentType();
+            }
+            return toArrayPreserveComponentType();
+        }
+
+        private Object[] toArrayWithoutComponentType() {
+            return Arrays.copyOf(a, a.length, Object[].class);
+        }
+
+        private Object[] toArrayPreserveComponentType() {
+            return a.clone();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                return Arrays.copyOf(this.a, size,
+                                     (Class<? extends T[]>) a.getClass());
+            System.arraycopy(this.a, 0, a, 0, size);
+            if (a.length > size)
+                a[size] = null;
+            return a;
+        }
+
+        @Override
+        public E get(int index) {
+            return a[index];
+        }
+
+        @Override
+        public E set(int index, E element) {
+            E oldValue = a[index];
+            a[index] = element;
+            return oldValue;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            E[] a = this.a;
+            if (o == null) {
+                for (int i = 0; i < a.length; i++)
+                    if (a[i] == null)
+                        return i;
+            } else {
+                for (int i = 0; i < a.length; i++)
+                    if (o.equals(a[i]))
+                        return i;
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return Spliterators.spliterator(a, Spliterator.ORDERED);
+        }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            for (E e : a) {
+                action.accept(e);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            E[] a = this.a;
+            for (int i = 0; i < a.length; i++) {
+                a[i] = operator.apply(a[i]);
+            }
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            Arrays.sort(a, c);
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new ArrayItr<>(a);
+        }
+    }
+
+    private static class ArrayItr<E> implements Iterator<E> {
+        private int cursor;
+        private final E[] a;
+
+        ArrayItr(E[] a) {
+            this.a = a;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return cursor < a.length;
+        }
+
+        @Override
+        public E next() {
+            int i = cursor;
+            if (i >= a.length) {
+                throw new NoSuchElementException();
+            }
+            cursor = i + 1;
+            return a[i];
+        }
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code long} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Long}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(long a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (long element : a) {
+            int elementHash = (int)(element ^ (element >>> 32));
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two non-null {@code int} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Integer}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(int a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (int element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code short} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Short}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(short a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (short element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code char} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Character}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(char a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (char element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code byte} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Byte}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(byte a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (byte element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code boolean} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Boolean}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(boolean a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (boolean element : a)
+            result = 31 * result + (element ? 1231 : 1237);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code float} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Float}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(float a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (float element : a)
+            result = 31 * result + Float.floatToIntBits(element);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two {@code double} arrays {@code a} and {@code b}
+     * such that {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() hashCode}
+     * method on a {@link List} containing a sequence of {@link Double}
+     * instances representing the elements of {@code a} in the same order.
+     * If {@code a} is {@code null}, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for {@code a}
+     * @since 1.5
+     */
+    public static int hashCode(double a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (double element : a) {
+            long bits = Double.doubleToLongBits(element);
+            result = 31 * result + (int)(bits ^ (bits >>> 32));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.  If
+     * the array contains other arrays as elements, the hash code is based on
+     * their identities rather than their contents.  It is therefore
+     * acceptable to invoke this method on an array that contains itself as an
+     * element,  either directly or indirectly through one or more levels of
+     * arrays.
+     *
+     * <p>For any two arrays {@code a} and {@code b} such that
+     * {@code Arrays.equals(a, b)}, it is also the case that
+     * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by {@code Arrays.asList(a).hashCode()}, unless {@code a}
+     * is {@code null}, in which case {@code 0} is returned.
+     *
+     * @param a the array whose content-based hash code to compute
+     * @return a content-based hash code for {@code a}
+     * @see #deepHashCode(Object[])
+     * @since 1.5
+     */
+    public static int hashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a)
+            result = 31 * result + (element == null ? 0 : element.hashCode());
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the
+     * hash code is based on their contents and so on, ad infinitum.
+     * It is therefore unacceptable to invoke this method on an array that
+     * contains itself as an element, either directly or indirectly through
+     * one or more levels of arrays.  The behavior of such an invocation is
+     * undefined.
+     *
+     * <p>For any two arrays {@code a} and {@code b} such that
+     * {@code Arrays.deepEquals(a, b)}, it is also the case that
+     * {@code Arrays.deepHashCode(a) == Arrays.deepHashCode(b)}.
+     *
+     * <p>The computation of the value returned by this method is similar to
+     * that of the value returned by {@link List#hashCode()} on a list
+     * containing the same elements as {@code a} in the same order, with one
+     * difference: If an element {@code e} of {@code a} is itself an array,
+     * its hash code is computed not by calling {@code e.hashCode()}, but as
+     * by calling the appropriate overloading of {@code Arrays.hashCode(e)}
+     * if {@code e} is an array of a primitive type, or as by calling
+     * {@code Arrays.deepHashCode(e)} recursively if {@code e} is an array
+     * of a reference type.  If {@code a} is {@code null}, this method
+     * returns 0.
+     *
+     * @param a the array whose deep-content-based hash code to compute
+     * @return a deep-content-based hash code for {@code a}
+     * @see #hashCode(Object[])
+     * @since 1.5
+     */
+    public static int deepHashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a) {
+            final int elementHash;
+            final Class<?> cl;
+            if (element == null)
+                elementHash = 0;
+            else if ((cl = element.getClass().getComponentType()) == null)
+                elementHash = element.hashCode();
+            else if (element instanceof Object[])
+                elementHash = deepHashCode((Object[]) element);
+            else
+                elementHash = primitiveArrayHashCode(element, cl);
+
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    private static int primitiveArrayHashCode(Object a, Class<?> cl) {
+        return
+            (cl == byte.class)    ? hashCode((byte[]) a)    :
+            (cl == int.class)     ? hashCode((int[]) a)     :
+            (cl == long.class)    ? hashCode((long[]) a)    :
+            (cl == char.class)    ? hashCode((char[]) a)    :
+            (cl == short.class)   ? hashCode((short[]) a)   :
+            (cl == boolean.class) ? hashCode((boolean[]) a) :
+            (cl == double.class)  ? hashCode((double[]) a)  :
+            // If new primitive types are ever added, this method must be
+            // expanded or we will fail here with ClassCastException.
+            hashCode((float[]) a);
+    }
+
+    /**
+     * Returns {@code true} if the two specified arrays are <i>deeply
+     * equal</i> to one another.  Unlike the {@link #equals(Object[],Object[])}
+     * method, this method is appropriate for use with nested arrays of
+     * arbitrary depth.
+     *
+     * <p>Two array references are considered deeply equal if both
+     * are {@code null}, or if they refer to arrays that contain the same
+     * number of elements and all corresponding pairs of elements in the two
+     * arrays are deeply equal.
+     *
+     * <p>Two possibly {@code null} elements {@code e1} and {@code e2} are
+     * deeply equal if any of the following conditions hold:
+     * <ul>
+     *    <li> {@code e1} and {@code e2} are both arrays of object reference
+     *         types, and {@code Arrays.deepEquals(e1, e2) would return true}
+     *    <li> {@code e1} and {@code e2} are arrays of the same primitive
+     *         type, and the appropriate overloading of
+     *         {@code Arrays.equals(e1, e2)} would return true.
+     *    <li> {@code e1 == e2}
+     *    <li> {@code e1.equals(e2)} would return true.
+     * </ul>
+     * Note that this definition permits {@code null} elements at any depth.
+     *
+     * <p>If either of the specified arrays contain themselves as elements
+     * either directly or indirectly through one or more levels of arrays,
+     * the behavior of this method is undefined.
+     *
+     * @param a1 one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return {@code true} if the two arrays are equal
+     * @see #equals(Object[],Object[])
+     * @see Objects#deepEquals(Object, Object)
+     * @since 1.5
+     */
+    public static boolean deepEquals(Object[] a1, Object[] a2) {
+        if (a1 == a2)
+            return true;
+        if (a1 == null || a2==null)
+            return false;
+        int length = a1.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i = 0; i < length; i++) {
+            Object e1 = a1[i];
+            Object e2 = a2[i];
+
+            if (e1 == e2)
+                continue;
+            if (e1 == null)
+                return false;
+
+            // Figure out whether the two elements are equal
+            boolean eq = deepEquals0(e1, e2);
+
+            if (!eq)
+                return false;
+        }
+        return true;
+    }
+
+    static boolean deepEquals0(Object e1, Object e2) {
+        assert e1 != null;
+        boolean eq;
+        if (e1 instanceof Object[] && e2 instanceof Object[])
+            eq = deepEquals ((Object[]) e1, (Object[]) e2);
+        else if (e1 instanceof byte[] && e2 instanceof byte[])
+            eq = equals((byte[]) e1, (byte[]) e2);
+        else if (e1 instanceof short[] && e2 instanceof short[])
+            eq = equals((short[]) e1, (short[]) e2);
+        else if (e1 instanceof int[] && e2 instanceof int[])
+            eq = equals((int[]) e1, (int[]) e2);
+        else if (e1 instanceof long[] && e2 instanceof long[])
+            eq = equals((long[]) e1, (long[]) e2);
+        else if (e1 instanceof char[] && e2 instanceof char[])
+            eq = equals((char[]) e1, (char[]) e2);
+        else if (e1 instanceof float[] && e2 instanceof float[])
+            eq = equals((float[]) e1, (float[]) e2);
+        else if (e1 instanceof double[] && e2 instanceof double[])
+            eq = equals((double[]) e1, (double[]) e2);
+        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
+            eq = equals((boolean[]) e1, (boolean[]) e2);
+        else
+            eq = e1.equals(e2);
+        return eq;
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(long)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(long[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(int)}.  Returns {@code "null"} if {@code a} is
+     * {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(int[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(short)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(short[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(char)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(char[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements
+     * are separated by the characters {@code ", "} (a comma followed
+     * by a space).  Elements are converted to strings as by
+     * {@code String.valueOf(byte)}.  Returns {@code "null"} if
+     * {@code a} is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(byte[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(boolean)}.  Returns {@code "null"} if
+     * {@code a} is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(boolean[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(float)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(float[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets ({@code "[]"}).  Adjacent elements are
+     * separated by the characters {@code ", "} (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * {@code String.valueOf(double)}.  Returns {@code "null"} if {@code a}
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @since 1.5
+     */
+    public static String toString(double[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * If the array contains other arrays as elements, they are converted to
+     * strings by the {@link Object#toString} method inherited from
+     * {@code Object}, which describes their <i>identities</i> rather than
+     * their contents.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by {@code Arrays.asList(a).toString()}, unless {@code a}
+     * is {@code null}, in which case {@code "null"} is returned.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @see #deepToString(Object[])
+     * @since 1.5
+     */
+    public static String toString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(String.valueOf(a[i]));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the string
+     * representation contains their contents and so on.  This method is
+     * designed for converting multidimensional arrays to strings.
+     *
+     * <p>The string representation consists of a list of the array's
+     * elements, enclosed in square brackets ({@code "[]"}).  Adjacent
+     * elements are separated by the characters {@code ", "} (a comma
+     * followed by a space).  Elements are converted to strings as by
+     * {@code String.valueOf(Object)}, unless they are themselves
+     * arrays.
+     *
+     * <p>If an element {@code e} is an array of a primitive type, it is
+     * converted to a string as by invoking the appropriate overloading of
+     * {@code Arrays.toString(e)}.  If an element {@code e} is an array of a
+     * reference type, it is converted to a string as by invoking
+     * this method recursively.
+     *
+     * <p>To avoid infinite recursion, if the specified array contains itself
+     * as an element, or contains an indirect reference to itself through one
+     * or more levels of arrays, the self-reference is converted to the string
+     * {@code "[...]"}.  For example, an array containing only a reference
+     * to itself would be rendered as {@code "[[...]]"}.
+     *
+     * <p>This method returns {@code "null"} if the specified array
+     * is {@code null}.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of {@code a}
+     * @see #toString(Object[])
+     * @since 1.5
+     */
+    public static String deepToString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int bufLen = 20 * a.length;
+        if (a.length != 0 && bufLen <= 0)
+            bufLen = Integer.MAX_VALUE;
+        StringBuilder buf = new StringBuilder(bufLen);
+        deepToString(a, buf, new HashSet<>());
+        return buf.toString();
+    }
+
+    private static void deepToString(Object[] a, StringBuilder buf,
+                                     Set<Object[]> dejaVu) {
+        if (a == null) {
+            buf.append("null");
+            return;
+        }
+        int iMax = a.length - 1;
+        if (iMax == -1) {
+            buf.append("[]");
+            return;
+        }
+
+        dejaVu.add(a);
+        buf.append('[');
+        for (int i = 0; ; i++) {
+
+            Object element = a[i];
+            if (element == null) {
+                buf.append("null");
+            } else {
+                Class<?> eClass = element.getClass();
+
+                if (eClass.isArray()) {
+                    if (eClass == byte[].class)
+                        buf.append(toString((byte[]) element));
+                    else if (eClass == short[].class)
+                        buf.append(toString((short[]) element));
+                    else if (eClass == int[].class)
+                        buf.append(toString((int[]) element));
+                    else if (eClass == long[].class)
+                        buf.append(toString((long[]) element));
+                    else if (eClass == char[].class)
+                        buf.append(toString((char[]) element));
+                    else if (eClass == float[].class)
+                        buf.append(toString((float[]) element));
+                    else if (eClass == double[].class)
+                        buf.append(toString((double[]) element));
+                    else if (eClass == boolean[].class)
+                        buf.append(toString((boolean[]) element));
+                    else { // element is an array of object references
+                        if (dejaVu.contains(element))
+                            buf.append("[...]");
+                        else
+                            deepToString((Object[])element, buf, dejaVu);
+                    }
+                } else {  // element is non-null and not an array
+                    buf.append(element.toString());
+                }
+            }
+            if (i == iMax)
+                break;
+            buf.append(", ");
+        }
+        buf.append(']');
+        dejaVu.remove(a);
+    }
+
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }</pre>
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.apply(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }</pre>
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsInt(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     * value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsLong(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, using a generator function to compute
+     * each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsDouble(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @apiNote
+     * Setting a subrange of an array, in parallel, using a generator function
+     * to compute each element, can be written as follows:
+     * <pre>{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }</pre>
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); });
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return the spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering all of the specified
+     * array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering the specified range of
+     * the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param <T> The type of the array elements
+     * @param array The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param <T> the type of the array elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code Stream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return an {@code IntStream} for the array
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return an {@code IntStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code LongStream} for the array
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code LongStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code DoubleStream} for the array
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code DoubleStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+
+    // Comparison methods
+
+    // Compare boolean
+
+    /**
+     * Compares two {@code boolean} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Boolean#compare(boolean, boolean)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(boolean[], boolean[])} for the definition of a
+     * common and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(boolean[], boolean[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Boolean.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(boolean[] a, boolean[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Boolean.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code boolean} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Boolean#compare(boolean, boolean)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(boolean[], int, int, boolean[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(boolean[], int, int, boolean[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(boolean[] a, int aFromIndex, int aToIndex,
+                              boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare byte
+
+    /**
+     * Compares two {@code byte} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Byte#compare(byte, byte)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(byte[], byte[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(byte[], byte[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(byte[] a, byte[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Byte.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code byte} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Byte#compare(byte, byte)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(byte[], int, int, byte[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(byte[] a, int aFromIndex, int aToIndex,
+                              byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code byte} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Byte#compareUnsigned(byte, byte)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(byte[], byte[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(byte[] a, byte[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Byte.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+
+    /**
+     * Compares two {@code byte} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Byte#compareUnsigned(byte, byte)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex,
+                                      byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare short
+
+    /**
+     * Compares two {@code short} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Short#compare(short, short)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(short[], short[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(short[], short[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(short[] a, short[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Short.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Short#compare(short, short)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(short[], int, int, short[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(short[], int, int, short[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(short[] a, int aFromIndex, int aToIndex,
+                              short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Short#compareUnsigned(short, short)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(short[], short[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(short[] a, short[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Short.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code short} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Short#compareUnsigned(short, short)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(short[], int, int, short[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(short[] a, int aFromIndex, int aToIndex,
+                                      short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare char
+
+    /**
+     * Compares two {@code char} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Character#compare(char, char)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(char[], char[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(char[], char[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Character.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(char[] a, char[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Character.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code char} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Character#compare(char, char)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(char[], int, int, char[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(char[], int, int, char[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(char[] a, int aFromIndex, int aToIndex,
+                              char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare int
+
+    /**
+     * Compares two {@code int} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Integer#compare(int, int)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(int[], int[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(int[], int[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(int[] a, int[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Integer.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Integer#compare(int, int)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(int[], int, int, int[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(int[], int, int, int[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(int[] a, int aFromIndex, int aToIndex,
+                              int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Integer#compareUnsigned(int, int)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(int[], int[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(int[] a, int[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Integer.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code int} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Integer#compareUnsigned(int, int)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(int[], int, int, int[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(int[] a, int aFromIndex, int aToIndex,
+                                      int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare long
+
+    /**
+     * Compares two {@code long} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Long#compare(long, long)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(long[], long[])} for the definition of a common and
+     * proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(long[], long[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(long[] a, long[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Long.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Long#compare(long, long)}, at a relative index
+     * within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(long[], int, int, long[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(long[], int, int, long[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(long[] a, int aFromIndex, int aToIndex,
+                              long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically, numerically treating
+     * elements as unsigned.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Long#compareUnsigned(long, long)}, at an index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(long[], long[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are
+     *         equal and contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compareUnsigned(long[] a, long[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Long.compareUnsigned(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code long} arrays lexicographically over the specified
+     * ranges, numerically treating elements as unsigned.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Long#compareUnsigned(long, long)}, at a
+     * relative index within the respective arrays that is the length of the
+     * prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(long[], int, int, long[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is null
+     * @since 9
+     */
+    public static int compareUnsigned(long[] a, int aFromIndex, int aToIndex,
+                                      long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare float
+
+    /**
+     * Compares two {@code float} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Float#compare(float, float)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(float[], float[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(float[], float[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Float.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(float[] a, float[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Float.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code float} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Float#compare(float, float)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(float[], int, int, float[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(float[], int, int, float[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(float[] a, int aFromIndex, int aToIndex,
+                              float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare double
+
+    /**
+     * Compares two {@code double} arrays lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements, as if by
+     * {@link Double#compare(double, double)}, at an index within the respective
+     * arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(double[], double[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(double[], double[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Double.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static int compare(double[] a, double[] b) {
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int i = ArraysSupport.mismatch(a, b,
+                                       Math.min(a.length, b.length));
+        if (i >= 0) {
+            return Double.compare(a[i], b[i]);
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code double} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements, as if by {@link Double#compare(double, double)}, at a relative
+     * index within the respective arrays that is the length of the prefix.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(double[], int, int, double[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(double[], int, int, double[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if:
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int compare(double[] a, int aFromIndex, int aToIndex,
+                              double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       Math.min(aLength, bLength));
+        if (i >= 0) {
+            return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+        }
+
+        return aLength - bLength;
+    }
+
+    // Compare objects
+
+    /**
+     * Compares two {@code Object} arrays, within comparable elements,
+     * lexicographically.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing two elements of type {@code T} at
+     * an index {@code i} within the respective arrays that is the prefix
+     * length, as if by:
+     * <pre>{@code
+     *     Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+     *         compare(a[i], b[i])
+     * }</pre>
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(Object[], Object[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference. Two {@code null} array
+     * references are considered equal.
+     * A {@code null} array element is considered lexicographically less than a
+     * non-{@code null} array element. Two {@code null} array elements are
+     * considered equal.
+     *
+     * <p>The comparison is consistent with {@link #equals(Object[], Object[]) equals},
+     * more specifically the following holds for arrays {@code a} and {@code b}:
+     * <pre>{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references
+     * and elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return a[i].compareTo(b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @param <T> the type of comparable array elements
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @since 9
+     */
+    public static <T extends Comparable<? super T>> int compare(T[] a, T[] b) {
+        if (a == b)
+            return 0;
+        // A null array is less than a non-null array
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int length = Math.min(a.length, b.length);
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // A null element is less than a non-null element
+                if (oa == null || ob == null)
+                    return oa == null ? -1 : 1;
+                int v = oa.compareTo(ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing two
+     * elements of type {@code T} at a relative index {@code i} within the
+     * respective arrays that is the prefix length, as if by:
+     * <pre>{@code
+     *     Comparator.nullsFirst(Comparator.<T>naturalOrder()).
+     *         compare(a[aFromIndex + i, b[bFromIndex + i])
+     * }</pre>
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * <p>The comparison is consistent with
+     * {@link #equals(Object[], int, int, Object[], int, int) equals}, more
+     * specifically the following holds for arrays {@code a} and {@code b} with
+     * specified ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively:
+     * <pre>{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }</pre>
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return a[aFromIndex + i].compareTo(b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @param <T> the type of comparable array elements
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static <T extends Comparable<? super T>> int compare(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                if (oa == null || ob == null)
+                    return oa == null ? -1 : 1;
+                int v = oa.compareTo(ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return aLength - bLength;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically using a specified
+     * comparator.
+     *
+     * <p>If the two arrays share a common prefix then the lexicographic
+     * comparison is the result of comparing with the specified comparator two
+     * elements at an index within the respective arrays that is the prefix
+     * length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two array lengths.
+     * (See {@link #mismatch(Object[], Object[])} for the definition of a common
+     * and proper prefix.)
+     *
+     * <p>A {@code null} array reference is considered lexicographically less
+     * than a non-{@code null} array reference.  Two {@code null} array
+     * references are considered equal.
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array references):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, b, cmp);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return cmp.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param b the second array to compare
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the value {@code 0} if the first and second array are equal and
+     *         contain the same elements in the same order;
+     *         a value less than {@code 0} if the first array is
+     *         lexicographically less than the second array; and
+     *         a value greater than {@code 0} if the first array is
+     *         lexicographically greater than the second array
+     * @throws NullPointerException if the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int compare(T[] a, T[] b,
+                                  Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        if (a == b)
+            return 0;
+        if (a == null || b == null)
+            return a == null ? -1 : 1;
+
+        int length = Math.min(a.length, b.length);
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return a.length - b.length;
+    }
+
+    /**
+     * Compares two {@code Object} arrays lexicographically over the specified
+     * ranges.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the lexicographic comparison is the result of comparing with the
+     * specified comparator two elements at a relative index within the
+     * respective arrays that is the prefix length.
+     * Otherwise, one array is a proper prefix of the other and, lexicographic
+     * comparison is the result of comparing the two range lengths.
+     * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the
+     * definition of a common and proper prefix.)
+     *
+     * @apiNote
+     * <p>This method behaves as if (for non-{@code null} array elements):
+     * <pre>{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex, cmp);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return cmp.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }</pre>
+     *
+     * @param a the first array to compare
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be compared
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be compared
+     * @param b the second array to compare
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be compared
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be compared
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the value {@code 0} if, over the specified ranges, the first and
+     *         second array are equal and contain the same elements in the same
+     *         order;
+     *         a value less than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically less than the second array; and
+     *         a value greater than {@code 0} if, over the specified ranges, the
+     *         first array is lexicographically greater than the second array
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int compare(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex,
+            Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return v;
+                }
+            }
+        }
+
+        return aLength - bLength;
+    }
+
+
+    // Mismatch methods
+
+    // Mismatch boolean
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code boolean} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(boolean[] a, boolean[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code boolean} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(boolean[] a, int aFromIndex, int aToIndex,
+                               boolean[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch byte
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code byte}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(byte[] a, byte[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code byte} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(byte[] a, int aFromIndex, int aToIndex,
+                               byte[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch char
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code char}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(char[] a, char[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code char} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(char[] a, int aFromIndex, int aToIndex,
+                               char[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch short
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code short}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(short[] a, short[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code short} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(short[] a, int aFromIndex, int aToIndex,
+                               short[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch int
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code int}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(int[] a, int[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code int} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(int[] a, int aFromIndex, int aToIndex,
+                               int[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch long
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code long}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(long[] a, long[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code long} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(long[] a, int aFromIndex, int aToIndex,
+                               long[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch float
+
+    /**
+     * Finds and returns the index of the first mismatch between two {@code float}
+     * arrays, otherwise return -1 if no mismatch is found.  The index will be
+     * in the range of 0 (inclusive) up to the length (inclusive) of the smaller
+     * array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Float.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(float[] a, float[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code float} arrays over the specified ranges, otherwise return -1 if no
+     * mismatch is found.  The index will be in the range of 0 (inclusive) up to
+     * the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Float.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(float[] a, int aFromIndex, int aToIndex,
+                               float[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch double
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code double} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Double.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(double[] a, double[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        int i = ArraysSupport.mismatch(a, b, length);
+        return (i < 0 && a.length != b.length) ? length : i;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code double} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Double.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(double[] a, int aFromIndex, int aToIndex,
+                               double[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        int i = ArraysSupport.mismatch(a, aFromIndex,
+                                       b, bFromIndex,
+                                       length);
+        return (i < 0 && aLength != bLength) ? length : i;
+    }
+
+    // Mismatch objects
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code Object} arrays, otherwise return -1 if no mismatch is found.  The
+     * index will be in the range of 0 (inclusive) up to the length (inclusive)
+     * of the smaller array.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     !Objects.equals(a[pl], b[pl])
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(Object[] a, Object[] b) {
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        for (int i = 0; i < length; i++) {
+            if (!Objects.equals(a[i], b[i]))
+                return i;
+        }
+
+        return a.length != b.length ? length : -1;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code Object} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     !Objects.equals(a[aFromIndex + pl], b[bFromIndex + pl])
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array is {@code null}
+     * @since 9
+     */
+    public static int mismatch(
+            Object[] a, int aFromIndex, int aToIndex,
+            Object[] b, int bFromIndex, int bToIndex) {
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            if (!Objects.equals(a[aFromIndex++], b[bFromIndex++]))
+                return i;
+        }
+
+        return aLength != bLength ? length : -1;
+    }
+
+    /**
+     * Finds and returns the index of the first mismatch between two
+     * {@code Object} arrays, otherwise return -1 if no mismatch is found.
+     * The index will be in the range of 0 (inclusive) up to the length
+     * (inclusive) of the smaller array.
+     *
+     * <p>The specified comparator is used to determine if two array elements
+     * from the each array are not equal.
+     *
+     * <p>If the two arrays share a common prefix then the returned index is the
+     * length of the common prefix and it follows that there is a mismatch
+     * between the two elements at that index within the respective arrays.
+     * If one array is a proper prefix of the other then the returned index is
+     * the length of the smaller array and it follows that the index is only
+     * valid for the larger array.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl, cmp)
+     *     cmp.compare(a[pl], b[pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b}, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length),
+     *                   cmp)
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param b the second array to be tested for a mismatch
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the index of the first mismatch between the two arrays,
+     *         otherwise {@code -1}.
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int mismatch(T[] a, T[] b, Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        int length = Math.min(a.length, b.length); // Check null array refs
+        if (a == b)
+            return -1;
+
+        for (int i = 0; i < length; i++) {
+            T oa = a[i];
+            T ob = b[i];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return i;
+                }
+            }
+        }
+
+        return a.length != b.length ? length : -1;
+    }
+
+    /**
+     * Finds and returns the relative index of the first mismatch between two
+     * {@code Object} arrays over the specified ranges, otherwise return -1 if
+     * no mismatch is found.  The index will be in the range of 0 (inclusive) up
+     * to the length (inclusive) of the smaller range.
+     *
+     * <p>If the two arrays, over the specified ranges, share a common prefix
+     * then the returned relative index is the length of the common prefix and
+     * it follows that there is a mismatch between the two elements at that
+     * relative index within the respective arrays.
+     * If one array is a proper prefix of the other, over the specified ranges,
+     * then the returned relative index is the length of the smaller range and
+     * it follows that the relative index is only valid for the array with the
+     * larger range.
+     * Otherwise, there is no mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common
+     * prefix of length {@code pl} if the following expression is true:
+     * <pre>{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
+     *     cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }</pre>
+     * Note that a common prefix length of {@code 0} indicates that the first
+     * elements from each array mismatch.
+     *
+     * <p>Two non-{@code null} arrays, {@code a} and {@code b} with specified
+     * ranges [{@code aFromIndex}, {@code atoIndex}) and
+     * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper
+     * prefix if the following expression is true:
+     * <pre>{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   cmp)
+     * }</pre>
+     *
+     * @param a the first array to be tested for a mismatch
+     * @param aFromIndex the index (inclusive) of the first element in the
+     *                   first array to be tested
+     * @param aToIndex the index (exclusive) of the last element in the
+     *                 first array to be tested
+     * @param b the second array to be tested for a mismatch
+     * @param bFromIndex the index (inclusive) of the first element in the
+     *                   second array to be tested
+     * @param bToIndex the index (exclusive) of the last element in the
+     *                 second array to be tested
+     * @param cmp the comparator to compare array elements
+     * @param <T> the type of array elements
+     * @return the relative index of the first mismatch between the two arrays
+     *         over the specified ranges, otherwise {@code -1}.
+     * @throws IllegalArgumentException
+     *         if {@code aFromIndex > aToIndex} or
+     *         if {@code bFromIndex > bToIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code aFromIndex < 0 or aToIndex > a.length} or
+     *         if {@code bFromIndex < 0 or bToIndex > b.length}
+     * @throws NullPointerException
+     *         if either array or the comparator is {@code null}
+     * @since 9
+     */
+    public static <T> int mismatch(
+            T[] a, int aFromIndex, int aToIndex,
+            T[] b, int bFromIndex, int bToIndex,
+            Comparator<? super T> cmp) {
+        Objects.requireNonNull(cmp);
+        rangeCheck(a.length, aFromIndex, aToIndex);
+        rangeCheck(b.length, bFromIndex, bToIndex);
+
+        int aLength = aToIndex - aFromIndex;
+        int bLength = bToIndex - bFromIndex;
+        int length = Math.min(aLength, bLength);
+        for (int i = 0; i < length; i++) {
+            T oa = a[aFromIndex++];
+            T ob = b[bFromIndex++];
+            if (oa != ob) {
+                // Null-value comparison is deferred to the comparator
+                int v = cmp.compare(oa, ob);
+                if (v != 0) {
+                    return i;
+                }
+            }
+        }
+
+        return aLength != bLength ? length : -1;
+    }
+}
diff --git a/android-35/java/util/ArraysParallelSortHelpers.java b/android-35/java/util/ArraysParallelSortHelpers.java
new file mode 100644
index 0000000..5fca0cd
--- /dev/null
+++ b/android-35/java/util/ArraysParallelSortHelpers.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.concurrent.CountedCompleter;
+
+/**
+ * Helper utilities for the parallel sort methods in Arrays.parallelSort.
+ *
+ * For each primitive type, plus Object, we define a static class to
+ * contain the Sorter and Merger implementations for that type:
+ *
+ * Sorter classes based mainly on CilkSort
+ * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
+ * Basic algorithm:
+ * if array size is small, just use a sequential sort (via Arrays.sort)
+ *         Otherwise:
+ *         1. Break array in half.
+ *         2. For each half,
+ *             a. break the half in half (i.e., quarters),
+ *             b. sort the quarters
+ *             c. merge them together
+ *         3. merge together the two halves.
+ *
+ * One reason for splitting in quarters is that this guarantees that
+ * the final sort is in the main array, not the workspace array.
+ * (workspace and main swap roles on each subsort step.)  Leaf-level
+ * sorts use the associated sequential sort.
+ *
+ * Merger classes perform merging for Sorter.  They are structured
+ * such that if the underlying sort is stable (as is true for
+ * TimSort), then so is the full sort.  If big enough, they split the
+ * largest of the two partitions in half, find the greatest point in
+ * smaller partition less than the beginning of the second half of
+ * larger via binary search; and then merge in parallel the two
+ * partitions.  In part to ensure tasks are triggered in
+ * stability-preserving order, the current CountedCompleter design
+ * requires some little tasks to serve as place holders for triggering
+ * completion tasks.  These classes (EmptyCompleter and Relay) don't
+ * need to keep track of the arrays, and are never themselves forked,
+ * so don't hold any task state.
+ *
+ * The base sequential sorts rely on non-public versions of TimSort,
+ * ComparableTimSort sort methods that accept temp workspace array
+ * slices that we will have already allocated, so avoids redundant
+ * allocation.
+ */
+/*package*/ class ArraysParallelSortHelpers {
+
+    /*
+     * Style note: The task classes have a lot of parameters, that are
+     * stored as task fields and copied to local variables and used in
+     * compute() methods, We pack these into as few lines as possible,
+     * and hoist consistency checks among them before main loops, to
+     * reduce distraction.
+     */
+
+    /**
+     * A placeholder task for Sorters, used for the lowest
+     * quartile task, that does not need to maintain array state.
+     */
+    static final class EmptyCompleter extends CountedCompleter<Void> {
+        @java.io.Serial
+        static final long serialVersionUID = 2446542900576103244L;
+        EmptyCompleter(CountedCompleter<?> p) { super(p); }
+        public final void compute() { }
+    }
+
+    /**
+     * A trigger for secondary merge of two merges
+     */
+    static final class Relay extends CountedCompleter<Void> {
+        @java.io.Serial
+        static final long serialVersionUID = 2446542900576103244L;
+        final CountedCompleter<?> task;
+        Relay(CountedCompleter<?> task) {
+            super(null, 1);
+            this.task = task;
+        }
+        public final void compute() { }
+        public final void onCompletion(CountedCompleter<?> t) {
+            task.compute();
+        }
+    }
+
+    /** Object + Comparator support class */
+    static final class FJObject {
+        static final class Sorter<T> extends CountedCompleter<Void> {
+            @java.io.Serial
+            static final long serialVersionUID = 2446542900576103244L;
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            final T[] a;
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            final T[] w;
+            final int base, size, wbase, gran;
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            Comparator<? super T> comparator;
+            Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,
+                   int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger<>(s, w, a, wb, h,
+                                                      wb+h, n-h, b, g, c));
+                    Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q,
+                                                      b+u, n-u, wb+h, g, c));
+                    new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork();
+                    new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork();
+                    Relay bc = new Relay(new Merger<>(fc, a, w, b, q,
+                                                      b+q, h-q, wb, g, c));
+                    new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                TimSort.sort(a, b, b + n, c, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger<T> extends CountedCompleter<Void> {
+            @java.io.Serial
+            static final long serialVersionUID = 2446542900576103244L;
+             // main and workspace arrays
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            final T[] a;
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            final T[] w;
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            @SuppressWarnings("serial") // Not statically typed as Serializable
+            Comparator<? super T> comparator;
+            Merger(CountedCompleter<?> par, T[] a, T[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+
+            public final void compute() {
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||
+                    c == null)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        T split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (c.compare(split, a[rm + rb]) <= 0)
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        T split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (c.compare(split, a[lm + lb]) <= 0)
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger<T> m = new Merger<>(this, a, w, lb + lh, ln - lh,
+                                               rb + rh, rn - rh,
+                                               k + lh + rh, g, c);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    T t, al, ar;
+                    if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+
+                tryComplete();
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/Base64.java b/android-35/java/util/Base64.java
new file mode 100644
index 0000000..3fe4572
--- /dev/null
+++ b/android-35/java/util/Base64.java
@@ -0,0 +1,1211 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.FilterOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+/**
+ * This class consists exclusively of static methods for obtaining
+ * encoders and decoders for the Base64 encoding scheme. The
+ * implementation of this class supports the following types of Base64
+ * as specified in
+ * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
+ *
+ * <ul>
+ * <li><a id="basic"><b>Basic</b></a>
+ * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 4648 and RFC 2045 for encoding and decoding operation.
+ *     The encoder does not add any line feed (line separator)
+ *     character. The decoder rejects data that contains characters
+ *     outside the base64 alphabet.</p></li>
+ *
+ * <li><a id="url"><b>URL and Filename safe</b></a>
+ * <p> Uses the "URL and Filename safe Base64 Alphabet" as specified
+ *     in Table 2 of RFC 4648 for encoding and decoding. The
+ *     encoder does not add any line feed (line separator) character.
+ *     The decoder rejects data that contains characters outside the
+ *     base64 alphabet.</p></li>
+ *
+ * <li><a id="mime"><b>MIME</b></a>
+ * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 2045 for encoding and decoding operation. The encoded output
+ *     must be represented in lines of no more than 76 characters each
+ *     and uses a carriage return {@code '\r'} followed immediately by
+ *     a linefeed {@code '\n'} as the line separator. No line separator
+ *     is added to the end of the encoded output. All line separators
+ *     or other characters not found in the base64 alphabet table are
+ *     ignored in decoding operation.</p></li>
+ * </ul>
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a
+ * method of this class will cause a {@link java.lang.NullPointerException
+ * NullPointerException} to be thrown.
+ *
+ * @author  Xueming Shen
+ * @since   1.8
+ */
+
+public class Base64 {
+
+    private Base64() {}
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getEncoder() {
+         return Encoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getUrlEncoder() {
+         return Encoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getMimeEncoder() {
+        return Encoder.RFC2045;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme
+     * with specified line length and line separators.
+     *
+     * @param   lineLength
+     *          the length of each output line (rounded down to nearest multiple
+     *          of 4). If the rounded down line length is not a positive value,
+     *          the output will not be separated in lines
+     * @param   lineSeparator
+     *          the line separator for each output line
+     *
+     * @return  A Base64 encoder.
+     *
+     * @throws  IllegalArgumentException if {@code lineSeparator} includes any
+     *          character of "The Base64 Alphabet" as specified in Table 1 of
+     *          RFC 2045.
+     */
+    public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) {
+         Objects.requireNonNull(lineSeparator);
+         int[] base64 = Decoder.fromBase64;
+         for (byte b : lineSeparator) {
+             if (base64[b & 0xff] != -1)
+                 throw new IllegalArgumentException(
+                     "Illegal base64 line separator character 0x" + Integer.toString(b, 16));
+         }
+         // round down to nearest multiple of 4
+         lineLength &= ~0b11;
+         if (lineLength <= 0) {
+             return Encoder.RFC4648;
+         }
+         return new Encoder(false, lineSeparator, lineLength, true);
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getDecoder() {
+         return Decoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getUrlDecoder() {
+         return Decoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#mime">MIME</a> type base64 decoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getMimeDecoder() {
+         return Decoder.RFC2045;
+    }
+
+    /**
+     * This class implements an encoder for encoding byte data using
+     * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> Instances of {@link Encoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     * <p> If the encoded byte output of the needed size can not
+     *     be allocated, the encode methods of this class will
+     *     cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
+     *     to be thrown.
+     *
+     * @see     Decoder
+     * @since   1.8
+     */
+    public static class Encoder {
+
+        private final byte[] newline;
+        private final int linemax;
+        private final boolean isURL;
+        private final boolean doPadding;
+
+        private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
+            this.isURL = isURL;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+        }
+
+        /**
+         * This array is a lookup table that translates 6-bit positive integer
+         * index values into their "Base64 Alphabet" equivalents as specified
+         * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648).
+         */
+        private static final char[] toBase64 = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+        };
+
+        /**
+         * It's the lookup table for "URL and Filename safe Base64" as specified
+         * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
+         * '_'. This table is used when BASE64_URL is specified.
+         */
+        private static final char[] toBase64URL = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+        };
+
+        private static final int MIMELINEMAX = 76;
+        private static final byte[] CRLF = new byte[] {'\r', '\n'};
+
+        static final Encoder RFC4648 = new Encoder(false, null, -1, true);
+        static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
+        static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
+
+        /**
+         * Calculates the length of the encoded output bytes.
+         *
+         * @param srclen length of the bytes to encode
+         * @param throwOOME if true, throws OutOfMemoryError if the length of
+         *                  the encoded bytes overflows; else returns the
+         *                  length
+         * @return length of the encoded bytes, or -1 if the length overflows
+         *
+         */
+        private final int encodedOutLength(int srclen, boolean throwOOME) {
+            int len = 0;
+            try {
+                if (doPadding) {
+                    len = Math.multiplyExact(4, (Math.addExact(srclen, 2) / 3));
+                } else {
+                    int n = srclen % 3;
+                    len = Math.addExact(Math.multiplyExact(4, (srclen / 3)), (n == 0 ? 0 : n + 1));
+                }
+                if (linemax > 0) {                             // line separators
+                    len = Math.addExact(len, (len - 1) / linemax * newline.length);
+                }
+            } catch (ArithmeticException ex) {
+                if (throwOOME) {
+                    throw new OutOfMemoryError("Encoded size is too large");
+                } else {
+                    // let the caller know that encoded bytes length
+                    // is too large
+                    len = -1;
+                }
+            }
+            return len;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array into a newly-allocated
+         * byte array using the {@link Base64} encoding scheme. The returned byte
+         * array is of the length of the resulting bytes.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A newly-allocated byte array containing the resulting
+         *          encoded bytes.
+         */
+        public byte[] encode(byte[] src) {
+            int len = encodedOutLength(src.length, true);          // dst array size
+            byte[] dst = new byte[len];
+            int ret = encode0(src, 0, src.length, dst);
+            if (ret != dst.length)
+                 return Arrays.copyOf(dst, ret);
+            return dst;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array using the
+         * {@link Base64} encoding scheme, writing the resulting bytes to the
+         * given output byte array, starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for encoding
+         * all bytes from the input byte array. No bytes will be written to the
+         * output byte array if the output byte array is not big enough.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @param   dst
+         *          the output byte array
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException if {@code dst} does not have enough
+         *          space for encoding all input bytes.
+         */
+        public int encode(byte[] src, byte[] dst) {
+            int len = encodedOutLength(src.length, false);         // dst array size
+            if (dst.length < len || len == -1)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for encoding all input bytes");
+            return encode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Encodes the specified byte array into a String using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> This method first encodes all input bytes into a base64 encoded
+         * byte array and then constructs a new String by using the encoded byte
+         * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
+         * ISO-8859-1} charset.
+         *
+         * <p> In other words, an invocation of this method has exactly the same
+         * effect as invoking
+         * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A String containing the resulting Base64 encoded characters
+         */
+        @SuppressWarnings("deprecation")
+        public String encodeToString(byte[] src) {
+            byte[] encoded = encode(src);
+            return new String(encoded, 0, 0, encoded.length);
+        }
+
+        /**
+         * Encodes all remaining bytes from the specified byte buffer into
+         * a newly-allocated ByteBuffer using the {@link Base64} encoding
+         * scheme.
+         *
+         * Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting encoded bytes.
+         *
+         * @param   buffer
+         *          the source ByteBuffer to encode
+         * @return  A newly-allocated byte buffer containing the encoded bytes.
+         */
+        public ByteBuffer encode(ByteBuffer buffer) {
+            int len = encodedOutLength(buffer.remaining(), true);
+            byte[] dst = new byte[len];
+            int ret = 0;
+            if (buffer.hasArray()) {
+                ret = encode0(buffer.array(),
+                              buffer.arrayOffset() + buffer.position(),
+                              buffer.arrayOffset() + buffer.limit(),
+                              dst);
+                buffer.position(buffer.limit());
+            } else {
+                byte[] src = new byte[buffer.remaining()];
+                buffer.get(src);
+                ret = encode0(src, 0, src.length, dst);
+            }
+            if (ret != dst.length)
+                 dst = Arrays.copyOf(dst, ret);
+            return ByteBuffer.wrap(dst);
+        }
+
+        /**
+         * Wraps an output stream for encoding byte data using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> It is recommended to promptly close the returned output stream after
+         * use, during which it will flush all possible leftover bytes to the underlying
+         * output stream. Closing the returned output stream will close the underlying
+         * output stream.
+         *
+         * @param   os
+         *          the output stream.
+         * @return  the output stream for encoding the byte data into the
+         *          specified Base64 encoded format
+         */
+        public OutputStream wrap(OutputStream os) {
+            Objects.requireNonNull(os);
+            return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
+                                       newline, linemax, doPadding);
+        }
+
+        /**
+         * Returns an encoder instance that encodes equivalently to this one,
+         * but without adding any padding character at the end of the encoded
+         * byte data.
+         *
+         * <p> The encoding scheme of this encoder instance is unaffected by
+         * this invocation. The returned encoder instance should be used for
+         * non-padding encoding operation.
+         *
+         * @return an equivalent encoder that encodes without adding any
+         *         padding character at the end
+         */
+        public Encoder withoutPadding() {
+            if (!doPadding)
+                return this;
+            return new Encoder(isURL, newline, linemax, false);
+        }
+
+        @IntrinsicCandidate
+        private void encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) {
+            char[] base64 = isURL ? toBase64URL : toBase64;
+            for (int sp0 = sp, dp0 = dp ; sp0 < sl; ) {
+                int bits = (src[sp0++] & 0xff) << 16 |
+                           (src[sp0++] & 0xff) <<  8 |
+                           (src[sp0++] & 0xff);
+                dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
+                dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
+                dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
+                dst[dp0++] = (byte)base64[bits & 0x3f];
+            }
+        }
+
+        private int encode0(byte[] src, int off, int end, byte[] dst) {
+            char[] base64 = isURL ? toBase64URL : toBase64;
+            int sp = off;
+            int slen = (end - off) / 3 * 3;
+            int sl = off + slen;
+            if (linemax > 0 && slen  > linemax / 4 * 3)
+                slen = linemax / 4 * 3;
+            int dp = 0;
+            while (sp < sl) {
+                int sl0 = Math.min(sp + slen, sl);
+                encodeBlock(src, sp, sl0, dst, dp, isURL);
+                int dlen = (sl0 - sp) / 3 * 4;
+                dp += dlen;
+                sp = sl0;
+                if (dlen == linemax && sp < end) {
+                    for (byte b : newline){
+                        dst[dp++] = b;
+                    }
+                }
+            }
+            if (sp < end) {               // 1 or 2 leftover bytes
+                int b0 = src[sp++] & 0xff;
+                dst[dp++] = (byte)base64[b0 >> 2];
+                if (sp == end) {
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                        dst[dp++] = '=';
+                    }
+                } else {
+                    int b1 = src[sp++] & 0xff;
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
+                    dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                    }
+                }
+            }
+            return dp;
+        }
+    }
+
+    /**
+     * This class implements a decoder for decoding byte data using the
+     * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> The Base64 padding character {@code '='} is accepted and
+     * interpreted as the end of the encoded byte data, but is not
+     * required. So if the final unit of the encoded byte data only has
+     * two or three Base64 characters (without the corresponding padding
+     * character(s) padded), they are decoded as if followed by padding
+     * character(s). If there is a padding character present in the
+     * final unit, the correct number of padding character(s) must be
+     * present, otherwise {@code IllegalArgumentException} (
+     * {@code IOException} when reading from a Base64 stream) is thrown
+     * during decoding.
+     *
+     * <p> Instances of {@link Decoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     * <p> If the decoded byte output of the needed size can not
+     *     be allocated, the decode methods of this class will
+     *     cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
+     *     to be thrown.
+     *
+     * @see     Encoder
+     * @since   1.8
+     */
+    public static class Decoder {
+
+        private final boolean isURL;
+        private final boolean isMIME;
+
+        private Decoder(boolean isURL, boolean isMIME) {
+            this.isURL = isURL;
+            this.isMIME = isMIME;
+        }
+
+        /**
+         * Lookup table for decoding unicode characters drawn from the
+         * "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
+         * their 6-bit positive integer equivalents.  Characters that
+         * are not in the Base64 alphabet but fall within the bounds of
+         * the array are encoded to -1.
+         *
+         */
+        private static final int[] fromBase64 = new int[256];
+        static {
+            Arrays.fill(fromBase64, -1);
+            for (int i = 0; i < Encoder.toBase64.length; i++)
+                fromBase64[Encoder.toBase64[i]] = i;
+            fromBase64['='] = -2;
+        }
+
+        /**
+         * Lookup table for decoding "URL and Filename safe Base64 Alphabet"
+         * as specified in Table2 of the RFC 4648.
+         */
+        private static final int[] fromBase64URL = new int[256];
+
+        static {
+            Arrays.fill(fromBase64URL, -1);
+            for (int i = 0; i < Encoder.toBase64URL.length; i++)
+                fromBase64URL[Encoder.toBase64URL[i]] = i;
+            fromBase64URL['='] = -2;
+        }
+
+        static final Decoder RFC4648         = new Decoder(false, false);
+        static final Decoder RFC4648_URLSAFE = new Decoder(true, false);
+        static final Decoder RFC2045         = new Decoder(false, true);
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated output
+         * byte array. The returned byte array is of the length of the resulting
+         * bytes.
+         *
+         * @param   src
+         *          the byte array to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(byte[] src) {
+            byte[] dst = new byte[decodedOutLength(src, 0, src.length)];
+            int ret = decode0(src, 0, src.length, dst);
+            if (ret != dst.length) {
+                dst = Arrays.copyOf(dst, ret);
+            }
+            return dst;
+        }
+
+        /**
+         * Decodes a Base64 encoded String into a newly-allocated byte array
+         * using the {@link Base64} encoding scheme.
+         *
+         * <p> An invocation of this method has exactly the same effect as invoking
+         * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))}
+         *
+         * @param   src
+         *          the string to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(String src) {
+            // Android-changed: keep Java 8 implementation.
+            // return decode(src.getBytes(ISO_8859_1.INSTANCE));
+            return decode(src.getBytes(StandardCharsets.ISO_8859_1));
+        }
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into the given output byte array,
+         * starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for decoding
+         * all bytes from the input byte array. No bytes will be written to
+         * the output byte array if the output byte array is not big enough.
+         *
+         * <p> If the input byte array is not in valid Base64 encoding scheme
+         * then some bytes may have been written to the output byte array before
+         * IllegalargumentException is thrown.
+         *
+         * @param   src
+         *          the byte array to decode
+         * @param   dst
+         *          the output byte array
+         *
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme, or {@code dst}
+         *          does not have enough space for decoding all input bytes.
+         */
+        public int decode(byte[] src, byte[] dst) {
+            int len = decodedOutLength(src, 0, src.length);
+            if (dst.length < len || len == -1)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for decoding all input bytes");
+            return decode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Decodes all bytes from the input byte buffer using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated ByteBuffer.
+         *
+         * <p> Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting decoded bytes
+         *
+         * <p> {@code IllegalArgumentException} is thrown if the input buffer
+         * is not in valid Base64 encoding scheme. The position of the input
+         * buffer will not be advanced in this case.
+         *
+         * @param   buffer
+         *          the ByteBuffer to decode
+         *
+         * @return  A newly-allocated byte buffer containing the decoded bytes
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code buffer} is not in valid Base64 scheme
+         */
+        public ByteBuffer decode(ByteBuffer buffer) {
+            int pos0 = buffer.position();
+            try {
+                byte[] src;
+                int sp, sl;
+                if (buffer.hasArray()) {
+                    src = buffer.array();
+                    sp = buffer.arrayOffset() + buffer.position();
+                    sl = buffer.arrayOffset() + buffer.limit();
+                    buffer.position(buffer.limit());
+                } else {
+                    src = new byte[buffer.remaining()];
+                    buffer.get(src);
+                    sp = 0;
+                    sl = src.length;
+                }
+                byte[] dst = new byte[decodedOutLength(src, sp, sl)];
+                return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
+            } catch (IllegalArgumentException iae) {
+                buffer.position(pos0);
+                throw iae;
+            }
+        }
+
+        /**
+         * Returns an input stream for decoding {@link Base64} encoded byte stream.
+         *
+         * <p> The {@code read}  methods of the returned {@code InputStream} will
+         * throw {@code IOException} when reading bytes that cannot be decoded.
+         *
+         * <p> Closing the returned input stream will close the underlying
+         * input stream.
+         *
+         * @param   is
+         *          the input stream
+         *
+         * @return  the input stream for decoding the specified Base64 encoded
+         *          byte stream
+         */
+        public InputStream wrap(InputStream is) {
+            Objects.requireNonNull(is);
+            return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
+        }
+
+        /**
+         * Calculates the length of the decoded output bytes.
+         *
+         * @param src the byte array to decode
+         * @param sp the source  position
+         * @param sl the source limit
+         *
+         * @return length of the decoded bytes
+         *
+         */
+        private int decodedOutLength(byte[] src, int sp, int sl) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int paddings = 0;
+            int len = sl - sp;
+            if (len == 0)
+                return 0;
+            if (len < 2) {
+                if (isMIME && base64[0] == -1)
+                    return 0;
+                throw new IllegalArgumentException(
+                    "Input byte[] should at least have 2 bytes for base64 bytes");
+            }
+            if (isMIME) {
+                // scan all bytes to fill out all non-alphabet. a performance
+                // trade-off of pre-scan or Arrays.copyOf
+                int n = 0;
+                while (sp < sl) {
+                    int b = src[sp++] & 0xff;
+                    if (b == '=') {
+                        len -= (sl - sp + 1);
+                        break;
+                    }
+                    if ((b = base64[b]) == -1)
+                        n++;
+                }
+                len -= n;
+            } else {
+                if (src[sl - 1] == '=') {
+                    paddings++;
+                    if (src[sl - 2] == '=')
+                        paddings++;
+                }
+            }
+            if (paddings == 0 && (len & 0x3) !=  0)
+                paddings = 4 - (len & 0x3);
+
+            // If len is near to Integer.MAX_VALUE, (len + 3)
+            // can possibly overflow, perform this operation as
+            // long and cast it back to integer when the value comes under
+            // integer limit. The final value will always be in integer
+            // limits
+            return 3 * (int) ((len + 3L) / 4) - paddings;
+        }
+
+        /**
+         * Decodes base64 characters, and returns the number of data bytes
+         * written into the destination array.
+         *
+         * It is the fast path for full 4-byte to 3-byte decoding w/o errors.
+         *
+         * decodeBlock() can be overridden by an arch-specific intrinsic.
+         * decodeBlock can choose to decode all, none, or a variable-sized
+         * prefix of the src bytes.  This allows the intrinsic to decode in
+         * chunks of the src that are of a favorable size for the specific
+         * processor it's running on.
+         *
+         * If any illegal base64 bytes are encountered in src by the
+         * intrinsic, the intrinsic must return the actual number of valid
+         * data bytes already written to dst.  Note that the '=' pad
+         * character is treated as an illegal Base64 character by
+         * decodeBlock, so it will not process a block of 4 bytes
+         * containing pad characters.  However, MIME decoding ignores
+         * illegal characters, so any intrinsic overriding decodeBlock
+         * can choose how to handle illegal characters based on the isMIME
+         * parameter.
+         *
+         * Given the parameters, no length check is possible on dst, so dst
+         * is assumed to be large enough to store the decoded bytes.
+         *
+         * @param  src
+         *         the source byte array of Base64 encoded bytes
+         * @param  sp
+         *         the offset into src array to begin reading
+         * @param  sl
+         *         the offset (exclusive) past the last byte to be converted.
+         * @param  dst
+         *         the destination byte array of decoded data bytes
+         * @param  dp
+         *         the offset into dst array to begin writing
+         * @param  isURL
+         *         boolean, when true decode RFC4648 URL-safe base64 characters
+         * @param  isMIME
+         *         boolean, when true decode according to RFC2045 (ignore illegal chars)
+         * @return the number of destination data bytes produced
+         */
+        @IntrinsicCandidate
+        private int decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, boolean isMIME) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int sl0 = sp + ((sl - sp) & ~0b11);
+            int new_dp = dp;
+            while (sp < sl0) {
+                int b1 = base64[src[sp++] & 0xff];
+                int b2 = base64[src[sp++] & 0xff];
+                int b3 = base64[src[sp++] & 0xff];
+                int b4 = base64[src[sp++] & 0xff];
+                if ((b1 | b2 | b3 | b4) < 0) {    // non base64 byte
+                    return new_dp - dp;
+                }
+                int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
+                dst[new_dp++] = (byte)(bits0 >> 16);
+                dst[new_dp++] = (byte)(bits0 >>  8);
+                dst[new_dp++] = (byte)(bits0);
+            }
+            return new_dp - dp;
+        }
+
+        private int decode0(byte[] src, int sp, int sl, byte[] dst) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int dp = 0;
+            int bits = 0;
+            int shiftto = 18;       // pos of first byte of 4-byte atom
+
+            while (sp < sl) {
+                if (shiftto == 18 && sp < sl - 4) {       // fast path
+                    int dl = decodeBlock(src, sp, sl, dst, dp, isURL, isMIME);
+                    /*
+                     * Calculate how many characters were processed by how many
+                     * bytes of data were returned.
+                     */
+                    int chars_decoded = ((dl + 2) / 3) * 4;
+
+                    sp += chars_decoded;
+                    dp += dl;
+                }
+                if (sp >= sl) {
+                    // we're done
+                    break;
+                }
+                int b = src[sp++] & 0xff;
+                if ((b = base64[b]) < 0) {
+                    if (b == -2) {         // padding byte '='
+                        // =     shiftto==18 unnecessary padding
+                        // x=    shiftto==12 a dangling single x
+                        // x     to be handled together with non-padding case
+                        // xx=   shiftto==6&&sp==sl missing last =
+                        // xx=y  shiftto==6 last is not =
+                        if (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
+                            shiftto == 18) {
+                            throw new IllegalArgumentException(
+                                "Input byte array has wrong 4-byte ending unit");
+                        }
+                        break;
+                    }
+                    if (isMIME)    // skip if for rfc2045
+                        continue;
+                    else
+                        throw new IllegalArgumentException(
+                            "Illegal base64 character " +
+                            Integer.toString(src[sp - 1], 16));
+                }
+                bits |= (b << shiftto);
+                shiftto -= 6;
+                if (shiftto < 0) {
+                    dst[dp++] = (byte)(bits >> 16);
+                    dst[dp++] = (byte)(bits >>  8);
+                    dst[dp++] = (byte)(bits);
+                    shiftto = 18;
+                    bits = 0;
+                }
+            }
+            // reached end of byte array or hit padding '=' characters.
+            if (shiftto == 6) {
+                dst[dp++] = (byte)(bits >> 16);
+            } else if (shiftto == 0) {
+                dst[dp++] = (byte)(bits >> 16);
+                dst[dp++] = (byte)(bits >>  8);
+            } else if (shiftto == 12) {
+                // dangling single "x", incorrectly encoded.
+                throw new IllegalArgumentException(
+                    "Last unit does not have enough valid bits");
+            }
+            // anything left is invalid, if is not MIME.
+            // if MIME, ignore all non-base64 character
+            while (sp < sl) {
+                if (isMIME && base64[src[sp++] & 0xff] < 0)
+                    continue;
+                throw new IllegalArgumentException(
+                    "Input byte array has incorrect ending byte at " + sp);
+            }
+            return dp;
+        }
+    }
+
+    /*
+     * An output stream for encoding bytes into the Base64.
+     */
+    private static class EncOutputStream extends FilterOutputStream {
+
+        private int leftover = 0;
+        private int b0, b1, b2;
+        private boolean closed = false;
+
+        private final char[] base64;    // byte->base64 mapping
+        private final byte[] newline;   // line separator, if needed
+        private final int linemax;
+        private final boolean doPadding;// whether or not to pad
+        private int linepos = 0;
+        private byte[] buf;
+
+        EncOutputStream(OutputStream os, char[] base64,
+                        byte[] newline, int linemax, boolean doPadding) {
+            super(os);
+            this.base64 = base64;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+            this.buf = new byte[linemax <= 0 ? 8124 : linemax];
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            byte[] buf = new byte[1];
+            buf[0] = (byte)(b & 0xff);
+            write(buf, 0, 1);
+        }
+
+        private void checkNewline() throws IOException {
+            if (linepos == linemax) {
+                out.write(newline);
+                linepos = 0;
+            }
+        }
+
+        private void writeb4(char b1, char b2, char b3, char b4) throws IOException {
+            buf[0] = (byte)b1;
+            buf[1] = (byte)b2;
+            buf[2] = (byte)b3;
+            buf[3] = (byte)b4;
+            out.write(buf, 0, 4);
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new ArrayIndexOutOfBoundsException();
+            if (len == 0)
+                return;
+            if (leftover != 0) {
+                if (leftover == 1) {
+                    b1 = b[off++] & 0xff;
+                    len--;
+                    if (len == 0) {
+                        leftover++;
+                        return;
+                    }
+                }
+                b2 = b[off++] & 0xff;
+                len--;
+                checkNewline();
+                writeb4(base64[b0 >> 2],
+                        base64[(b0 << 4) & 0x3f | (b1 >> 4)],
+                        base64[(b1 << 2) & 0x3f | (b2 >> 6)],
+                        base64[b2 & 0x3f]);
+                linepos += 4;
+            }
+            int nBits24 = len / 3;
+            leftover = len - (nBits24 * 3);
+
+            while (nBits24 > 0) {
+                checkNewline();
+                int dl = linemax <= 0 ? buf.length : buf.length - linepos;
+                int sl = off + Math.min(nBits24, dl / 4) * 3;
+                int dp = 0;
+                for (int sp = off; sp < sl; ) {
+                    int bits = (b[sp++] & 0xff) << 16 |
+                               (b[sp++] & 0xff) <<  8 |
+                               (b[sp++] & 0xff);
+                    buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f];
+                    buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f];
+                    buf[dp++] = (byte)base64[(bits >>> 6)  & 0x3f];
+                    buf[dp++] = (byte)base64[bits & 0x3f];
+                }
+                out.write(buf, 0, dp);
+                off = sl;
+                linepos += dp;
+                nBits24 -= dp / 4;
+            }
+            if (leftover == 1) {
+                b0 = b[off++] & 0xff;
+            } else if (leftover == 2) {
+                b0 = b[off++] & 0xff;
+                b1 = b[off++] & 0xff;
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                if (leftover == 1) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f]);
+                    if (doPadding) {
+                        out.write('=');
+                        out.write('=');
+                    }
+                } else if (leftover == 2) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
+                    out.write(base64[(b1 << 2) & 0x3f]);
+                    if (doPadding) {
+                       out.write('=');
+                    }
+                }
+                leftover = 0;
+                out.close();
+            }
+        }
+    }
+
+    /*
+     * An input stream for decoding Base64 bytes
+     */
+    private static class DecInputStream extends InputStream {
+
+        private final InputStream is;
+        private final boolean isMIME;
+        private final int[] base64;     // base64 -> byte mapping
+        private int bits = 0;           // 24-bit buffer for decoding
+
+        /* writing bit pos inside bits; one of 24 (left, msb), 18, 12, 6, 0 */
+        private int wpos = 0;
+
+        /* reading bit pos inside bits: one of 24 (left, msb), 16, 8, 0 */
+        private int rpos = 0;
+
+        private boolean eof = false;
+        private boolean closed = false;
+
+        DecInputStream(InputStream is, int[] base64, boolean isMIME) {
+            this.is = is;
+            this.base64 = base64;
+            this.isMIME = isMIME;
+        }
+
+        private byte[] sbBuf = new byte[1];
+
+        @Override
+        public int read() throws IOException {
+            return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
+        }
+
+        private int leftovers(byte[] b, int off, int pos, int limit) {
+            eof = true;
+
+            /*
+             * We use a loop here, as this method is executed only a few times.
+             * Unrolling the loop would probably not contribute much here.
+             */
+            while (rpos - 8 >= wpos && pos != limit) {
+                rpos -= 8;
+                b[pos++] = (byte) (bits >> rpos);
+            }
+            return pos - off != 0 || rpos - 8 >= wpos ? pos - off : -1;
+        }
+
+        private int eof(byte[] b, int off, int pos, int limit) throws IOException {
+            /*
+             * pos != limit
+             *
+             * wpos == 18: x     dangling single x, invalid unit
+             * accept ending xx or xxx without padding characters
+             */
+            if (wpos == 18) {
+                throw new IOException("Base64 stream has one un-decoded dangling byte.");
+            }
+            rpos = 24;
+            return leftovers(b, off, pos, limit);
+        }
+
+        private int padding(byte[] b, int off, int pos, int limit) throws IOException {
+            /*
+             * pos != limit
+             *
+             * wpos == 24: =    (unnecessary padding)
+             * wpos == 18: x=   (dangling single x, invalid unit)
+             * wpos == 12 and missing last '=': xx=  (invalid padding)
+             * wpos == 12 and last is not '=': xx=x (invalid padding)
+             */
+            if (wpos >= 18 || wpos == 12 && is.read() != '=') {
+                throw new IOException("Illegal base64 ending sequence:" + wpos);
+            }
+            rpos = 24;
+            return leftovers(b, off, pos, limit);
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (closed) {
+                throw new IOException("Stream is closed");
+            }
+            Objects.checkFromIndexSize(off, len, b.length);
+            if (len == 0) {
+                return 0;
+            }
+
+            /*
+             * Rather than keeping 2 running vars (e.g., off and len),
+             * we only keep one (pos), while definitely fixing the boundaries
+             * of the range [off, limit).
+             * More specifically, each use of pos as an index in b meets
+             *      pos - off >= 0 & limit - pos > 0
+             *
+             * Note that limit can overflow to Integer.MIN_VALUE. However,
+             * as long as comparisons with pos are as coded, there's no harm.
+             */
+            int pos = off;
+            final int limit = off + len;
+            if (eof) {
+                return leftovers(b, off, pos, limit);
+            }
+
+            /*
+             * Leftovers from previous invocation; here, wpos = 0.
+             * There can be at most 2 leftover bytes (rpos <= 16).
+             * Further, b has at least one free place.
+             *
+             * The logic could be coded as a loop, (as in method leftovers())
+             * but the explicit "unrolling" makes it possible to generate
+             * better byte extraction code.
+             */
+            if (rpos == 16) {
+                b[pos++] = (byte) (bits >> 8);
+                rpos = 8;
+                if (pos == limit) {
+                    return len;
+                }
+            }
+            if (rpos == 8) {
+                b[pos++] = (byte) bits;
+                rpos = 0;
+                if (pos == limit) {
+                    return len;
+                }
+            }
+
+            bits = 0;
+            wpos = 24;
+            for (;;) {
+                /* pos != limit & rpos == 0 */
+                final int i = is.read();
+                if (i < 0) {
+                    return eof(b, off, pos, limit);
+                }
+                final int v = base64[i];
+                if (v < 0) {
+                    /*
+                     * i not in alphabet, thus
+                     *      v == -2: i is '=', the padding
+                     *      v == -1: i is something else, typically CR or LF
+                     */
+                    if (v == -1) {
+                        if (isMIME) {
+                            continue;
+                        }
+                        throw new IOException("Illegal base64 character 0x" +
+                                Integer.toHexString(i));
+                    }
+                    return padding(b, off, pos, limit);
+                }
+                wpos -= 6;
+                bits |= v << wpos;
+                if (wpos != 0) {
+                    continue;
+                }
+                if (limit - pos >= 3) {
+                    /* frequently taken fast path, no need to track rpos */
+                    b[pos++] = (byte) (bits >> 16);
+                    b[pos++] = (byte) (bits >> 8);
+                    b[pos++] = (byte) bits;
+                    bits = 0;
+                    wpos = 24;
+                    if (pos == limit) {
+                        return len;
+                    }
+                    continue;
+                }
+
+                /* b has either 1 or 2 free places */
+                b[pos++] = (byte) (bits >> 16);
+                if (pos == limit) {
+                    rpos = 16;
+                    return len;
+                }
+                b[pos++] = (byte) (bits >> 8);
+                /* pos == limit, no need for an if */
+                rpos = 8;
+                return len;
+            }
+        }
+
+        @Override
+        public int available() throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            return is.available();   // TBD:
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                is.close();
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/BitSet.java b/android-35/java/util/BitSet.java
new file mode 100644
index 0000000..e0dc042
--- /dev/null
+++ b/android-35/java/util/BitSet.java
@@ -0,0 +1,1401 @@
+/*
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.LongBuffer;
+import java.util.function.IntConsumer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class implements a vector of bits that grows as needed. Each
+ * component of the bit set has a {@code boolean} value. The
+ * bits of a {@code BitSet} are indexed by nonnegative integers.
+ * Individual indexed bits can be examined, set, or cleared. One
+ * {@code BitSet} may be used to modify the contents of another
+ * {@code BitSet} through logical AND, logical inclusive OR, and
+ * logical exclusive OR operations.
+ *
+ * <p>By default, all bits in the set initially have the value
+ * {@code false}.
+ *
+ * <p>Every bit set has a current size, which is the number of bits
+ * of space currently in use by the bit set. Note that the size is
+ * related to the implementation of a bit set, so it may change with
+ * implementation. The length of a bit set relates to logical length
+ * of a bit set and is defined independently of implementation.
+ *
+ * <p>Unless otherwise noted, passing a null parameter to any of the
+ * methods in a {@code BitSet} will result in a
+ * {@code NullPointerException}.
+ *
+ * <p>A {@code BitSet} is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Martin Buchholz
+ * @since   1.0
+ */
+public class BitSet implements Cloneable, java.io.Serializable {
+    /*
+     * BitSets are packed into arrays of "words."  Currently a word is
+     * a long, which consists of 64 bits, requiring 6 address bits.
+     * The choice of word size is determined purely by performance concerns.
+     */
+    private static final int ADDRESS_BITS_PER_WORD = 6;
+    private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+    private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1;
+
+    /* Used to shift left or right for a partial word mask */
+    private static final long WORD_MASK = 0xffffffffffffffffL;
+
+    /**
+     * @serialField bits long[]
+     *
+     * The bits in this BitSet.  The ith bit is stored in bits[i/64] at
+     * bit position i % 64 (where bit position 0 refers to the least
+     * significant bit and 63 refers to the most significant bit).
+     */
+    @java.io.Serial
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("bits", long[].class),
+    };
+
+    /**
+     * The internal field corresponding to the serialField "bits".
+     */
+    private long[] words;
+
+    /**
+     * The number of words in the logical size of this BitSet.
+     */
+    private transient int wordsInUse = 0;
+
+    /**
+     * Whether the size of "words" is user-specified.  If so, we assume
+     * the user knows what he's doing and try harder to preserve it.
+     */
+    private transient boolean sizeIsSticky = false;
+
+    /* use serialVersionUID from JDK 1.0.2 for interoperability */
+    @java.io.Serial
+    private static final long serialVersionUID = 7997698588986878753L;
+
+    /**
+     * Given a bit index, return word index containing it.
+     */
+    private static int wordIndex(int bitIndex) {
+        return bitIndex >> ADDRESS_BITS_PER_WORD;
+    }
+
+    /**
+     * Every public method must preserve these invariants.
+     */
+    private void checkInvariants() {
+        assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
+        assert(wordsInUse >= 0 && wordsInUse <= words.length);
+        assert(wordsInUse == words.length || words[wordsInUse] == 0);
+    }
+
+    /**
+     * Sets the field wordsInUse to the logical size in words of the bit set.
+     * WARNING:This method assumes that the number of words actually in use is
+     * less than or equal to the current value of wordsInUse!
+     */
+    private void recalculateWordsInUse() {
+        // Traverse the bitset until a used word is found
+        int i;
+        for (i = wordsInUse-1; i >= 0; i--)
+            if (words[i] != 0)
+                break;
+
+        wordsInUse = i+1; // The new logical size
+    }
+
+    /**
+     * Creates a new bit set. All bits are initially {@code false}.
+     */
+    public BitSet() {
+        initWords(BITS_PER_WORD);
+        sizeIsSticky = false;
+    }
+
+    /**
+     * Creates a bit set whose initial size is large enough to explicitly
+     * represent bits with indices in the range {@code 0} through
+     * {@code nbits-1}. All bits are initially {@code false}.
+     *
+     * @param  nbits the initial size of the bit set
+     * @throws NegativeArraySizeException if the specified initial size
+     *         is negative
+     */
+    public BitSet(int nbits) {
+        // nbits can't be negative; size 0 is OK
+        if (nbits < 0)
+            throw new NegativeArraySizeException("nbits < 0: " + nbits);
+
+        initWords(nbits);
+        sizeIsSticky = true;
+    }
+
+    private void initWords(int nbits) {
+        words = new long[wordIndex(nbits-1) + 1];
+    }
+
+    /**
+     * Creates a bit set using words as the internal representation.
+     * The last word (if there is one) must be non-zero.
+     */
+    private BitSet(long[] words) {
+        this.words = words;
+        this.wordsInUse = words.length;
+        checkInvariants();
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
+     *
+     * @param longs a long array containing a little-endian representation
+     *        of a sequence of bits to be used as the initial bits of the
+     *        new bit set
+     * @return a {@code BitSet} containing all the bits in the long array
+     * @since 1.7
+     */
+    public static BitSet valueOf(long[] longs) {
+        int n;
+        for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
+            ;
+        return new BitSet(Arrays.copyOf(longs, n));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * lb.remaining()}.
+     *
+     * <p>The long buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param lb a long buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(LongBuffer lb) {
+        lb = lb.slice();
+        int n;
+        for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[n];
+        lb.get(words);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n <  8 * bytes.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
+     *
+     * @param bytes a byte array containing a little-endian
+     *        representation of a sequence of bits to be used as the
+     *        initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the byte array
+     * @since 1.7
+     */
+    public static BitSet valueOf(byte[] bytes) {
+        return BitSet.valueOf(ByteBuffer.wrap(bytes));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bb.remaining()}.
+     *
+     * <p>The byte buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param bb a byte buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(ByteBuffer bb) {
+        bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
+        int n;
+        for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[(n + 7) / 8];
+        bb.limit(n);
+        int i = 0;
+        while (bb.remaining() >= 8)
+            words[i++] = bb.getLong();
+        for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
+            words[i] |= (bb.get() & 0xffL) << (8 * j);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new byte array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code byte[] bytes = s.toByteArray();}
+     * <br>then {@code bytes.length == (s.length()+7)/8} and
+     * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bytes.length}.
+     *
+     * @return a byte array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+     */
+    public byte[] toByteArray() {
+        int n = wordsInUse;
+        if (n == 0)
+            return new byte[0];
+        int len = 8 * (n-1);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            len++;
+        byte[] bytes = new byte[len];
+        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+        for (int i = 0; i < n - 1; i++)
+            bb.putLong(words[i]);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            bb.put((byte) (x & 0xff));
+        return bytes;
+    }
+
+    /**
+     * Returns a new long array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code long[] longs = s.toLongArray();}
+     * <br>then {@code longs.length == (s.length()+63)/64} and
+     * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * @return a long array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+     */
+    public long[] toLongArray() {
+        return Arrays.copyOf(words, wordsInUse);
+    }
+
+    /**
+     * Ensures that the BitSet can hold enough words.
+     * @param wordsRequired the minimum acceptable number of words.
+     */
+    private void ensureCapacity(int wordsRequired) {
+        if (words.length < wordsRequired) {
+            // Allocate larger of doubled size or required size
+            int request = Math.max(2 * words.length, wordsRequired);
+            words = Arrays.copyOf(words, request);
+            sizeIsSticky = false;
+        }
+    }
+
+    /**
+     * Ensures that the BitSet can accommodate a given wordIndex,
+     * temporarily violating the invariants.  The caller must
+     * restore the invariants before returning to the user,
+     * possibly using recalculateWordsInUse().
+     * @param wordIndex the index to be accommodated.
+     */
+    private void expandTo(int wordIndex) {
+        int wordsRequired = wordIndex+1;
+        if (wordsInUse < wordsRequired) {
+            ensureCapacity(wordsRequired);
+            wordsInUse = wordsRequired;
+        }
+    }
+
+    /**
+     * Checks that fromIndex ... toIndex is a valid range of bit indices.
+     */
+    private static void checkRange(int fromIndex, int toIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+        if (toIndex < 0)
+            throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
+                                                " > toIndex: " + toIndex);
+    }
+
+    /**
+     * Sets the bit at the specified index to the complement of its
+     * current value.
+     *
+     * @param  bitIndex the index of the bit to flip
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void flip(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] ^= (1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets each bit from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the complement of its current
+     * value.
+     *
+     * @param  fromIndex index of the first bit to flip
+     * @param  toIndex index after the last bit to flip
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void flip(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] ^= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] ^= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] ^= WORD_MASK;
+
+            // Handle last word
+            words[endWordIndex] ^= lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to {@code true}.
+     *
+     * @param  bitIndex a bit index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.0
+     */
+    public void set(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] |= (1L << bitIndex); // Restores invariants
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to the specified value.
+     *
+     * @param  bitIndex a bit index
+     * @param  value a boolean value to set
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void set(int bitIndex, boolean value) {
+        if (value)
+            set(bitIndex);
+        else
+            clear(bitIndex);
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code true}.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        // Increase capacity if necessary
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] |= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] |= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = WORD_MASK;
+
+            // Handle last word (restores invariants)
+            words[endWordIndex] |= lastWordMask;
+        }
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the specified value.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @param  value value to set the selected bits to
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex, boolean value) {
+        if (value)
+            set(fromIndex, toIndex);
+        else
+            clear(fromIndex, toIndex);
+    }
+
+    /**
+     * Sets the bit specified by the index to {@code false}.
+     *
+     * @param  bitIndex the index of the bit to be cleared
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.0
+     */
+    public void clear(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        if (wordIndex >= wordsInUse)
+            return;
+
+        words[wordIndex] &= ~(1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code false}.
+     *
+     * @param  fromIndex index of the first bit to be cleared
+     * @param  toIndex index after the last bit to be cleared
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void clear(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        if (startWordIndex >= wordsInUse)
+            return;
+
+        int endWordIndex = wordIndex(toIndex - 1);
+        if (endWordIndex >= wordsInUse) {
+            toIndex = length();
+            endWordIndex = wordsInUse - 1;
+        }
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] &= ~(firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] &= ~firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = 0;
+
+            // Handle last word
+            words[endWordIndex] &= ~lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets all of the bits in this BitSet to {@code false}.
+     *
+     * @since 1.4
+     */
+    public void clear() {
+        while (wordsInUse > 0)
+            words[--wordsInUse] = 0;
+    }
+
+    /**
+     * Returns the value of the bit with the specified index. The value
+     * is {@code true} if the bit with the index {@code bitIndex}
+     * is currently set in this {@code BitSet}; otherwise, the result
+     * is {@code false}.
+     *
+     * @param  bitIndex   the bit index
+     * @return the value of the bit with the specified index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public boolean get(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        checkInvariants();
+
+        int wordIndex = wordIndex(bitIndex);
+        return (wordIndex < wordsInUse)
+            && ((words[wordIndex] & (1L << bitIndex)) != 0);
+    }
+
+    /**
+     * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
+     * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
+     *
+     * @param  fromIndex index of the first bit to include
+     * @param  toIndex index after the last bit to include
+     * @return a new {@code BitSet} from a range of this {@code BitSet}
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public BitSet get(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        checkInvariants();
+
+        int len = length();
+
+        // If no set bits in range return empty bitset
+        if (len <= fromIndex || fromIndex == toIndex)
+            return new BitSet(0);
+
+        // An optimization
+        if (toIndex > len)
+            toIndex = len;
+
+        BitSet result = new BitSet(toIndex - fromIndex);
+        int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
+        int sourceIndex = wordIndex(fromIndex);
+        boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
+
+        // Process all words but the last word
+        for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
+            result.words[i] = wordAligned ? words[sourceIndex] :
+                (words[sourceIndex] >>> fromIndex) |
+                (words[sourceIndex+1] << -fromIndex);
+
+        // Process the last word
+        long lastWordMask = WORD_MASK >>> -toIndex;
+        result.words[targetWords - 1] =
+            ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
+            ? /* straddles source words */
+            ((words[sourceIndex] >>> fromIndex) |
+             (words[sourceIndex+1] & lastWordMask) << -fromIndex)
+            :
+            ((words[sourceIndex] & lastWordMask) >>> fromIndex);
+
+        // Set wordsInUse correctly
+        result.wordsInUse = targetWords;
+        result.recalculateWordsInUse();
+        result.checkInvariants();
+
+        return result;
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code true}
+     * that occurs on or after the specified starting index. If no such
+     * bit exists then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+     *     // operate on index i here
+     *     if (i == Integer.MAX_VALUE) {
+     *         break; // or (i+1) would overflow
+     *     }
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextSetBit(int fromIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return -1;
+
+        long word = words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code false}
+     * that occurs on or after the specified starting index.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next clear bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextClearBit(int fromIndex) {
+        // Neither spec nor implementation handle bitsets of maximal length.
+        // See 4816253.
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return wordsInUse * BITS_PER_WORD;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code true}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
+     *     // operate on index i here
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousSetBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return length() - 1;
+
+        long word = words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code false}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous clear bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousClearBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the "logical size" of this {@code BitSet}: the index of
+     * the highest set bit in the {@code BitSet} plus one. Returns zero
+     * if the {@code BitSet} contains no set bits.
+     *
+     * @return the logical size of this {@code BitSet}
+     * @since  1.2
+     */
+    public int length() {
+        if (wordsInUse == 0)
+            return 0;
+
+        return BITS_PER_WORD * (wordsInUse - 1) +
+            (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
+    }
+
+    /**
+     * Returns true if this {@code BitSet} contains no bits that are set
+     * to {@code true}.
+     *
+     * @return boolean indicating whether this {@code BitSet} is empty
+     * @since  1.4
+     */
+    public boolean isEmpty() {
+        return wordsInUse == 0;
+    }
+
+    /**
+     * Returns true if the specified {@code BitSet} has any bits set to
+     * {@code true} that are also set to {@code true} in this {@code BitSet}.
+     *
+     * @param  set {@code BitSet} to intersect with
+     * @return boolean indicating whether this {@code BitSet} intersects
+     *         the specified {@code BitSet}
+     * @since  1.4
+     */
+    public boolean intersects(BitSet set) {
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            if ((words[i] & set.words[i]) != 0)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the number of bits set to {@code true} in this {@code BitSet}.
+     *
+     * @return the number of bits set to {@code true} in this {@code BitSet}
+     * @since  1.4
+     */
+    public int cardinality() {
+        int sum = 0;
+        for (int i = 0; i < wordsInUse; i++)
+            sum += Long.bitCount(words[i]);
+        return sum;
+    }
+
+    /**
+     * Performs a logical <b>AND</b> of this target bit set with the
+     * argument bit set. This bit set is modified so that each bit in it
+     * has the value {@code true} if and only if it both initially
+     * had the value {@code true} and the corresponding bit in the
+     * bit set argument also had the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void and(BitSet set) {
+        if (this == set)
+            return;
+
+        while (wordsInUse > set.wordsInUse)
+            words[--wordsInUse] = 0;
+
+        // Perform logical AND on words in common
+        for (int i = 0; i < wordsInUse; i++)
+            words[i] &= set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>OR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if it either already had the
+     * value {@code true} or the corresponding bit in the bit set
+     * argument has the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void or(BitSet set) {
+        if (this == set)
+            return;
+
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical OR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] |= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             wordsInUse - wordsInCommon);
+
+        // recalculateWordsInUse() is unnecessary
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>XOR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if one of the following
+     * statements holds:
+     * <ul>
+     * <li>The bit initially has the value {@code true}, and the
+     *     corresponding bit in the argument has the value {@code false}.
+     * <li>The bit initially has the value {@code false}, and the
+     *     corresponding bit in the argument has the value {@code true}.
+     * </ul>
+     *
+     * @param  set a bit set
+     */
+    public void xor(BitSet set) {
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical XOR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] ^= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             set.wordsInUse - wordsInCommon);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Clears all of the bits in this {@code BitSet} whose corresponding
+     * bit is set in the specified {@code BitSet}.
+     *
+     * @param  set the {@code BitSet} with which to mask this
+     *         {@code BitSet}
+     * @since  1.2
+     */
+    public void andNot(BitSet set) {
+        // Perform logical (a & !b) on words in common
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            words[i] &= ~set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Returns the hash code value for this bit set. The hash code depends
+     * only on which bits are set within this {@code BitSet}.
+     *
+     * <p>The hash code is defined to be the result of the following
+     * calculation:
+     *  <pre> {@code
+     * public int hashCode() {
+     *     long h = 1234;
+     *     long[] words = toLongArray();
+     *     for (int i = words.length; --i >= 0; )
+     *         h ^= words[i] * (i + 1);
+     *     return (int)((h >> 32) ^ h);
+     * }}</pre>
+     * Note that the hash code changes if the set of bits is altered.
+     *
+     * @return the hash code value for this bit set
+     */
+    public int hashCode() {
+        long h = 1234;
+        for (int i = wordsInUse; --i >= 0; )
+            h ^= words[i] * (i + 1);
+
+        return (int)((h >> 32) ^ h);
+    }
+
+    /**
+     * Returns the number of bits of space actually in use by this
+     * {@code BitSet} to represent bit values.
+     * The maximum element in the set is the size - 1st element.
+     *
+     * @return the number of bits currently in this bit set
+     */
+    public int size() {
+        return words.length * BITS_PER_WORD;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and is a {@code BitSet} object that has
+     * exactly the same set of bits set to {@code true} as this bit
+     * set. That is, for every nonnegative {@code int} index {@code k},
+     * <pre>((BitSet)obj).get(k) == this.get(k)</pre>
+     * must be true. The current sizes of the two bit sets are not compared.
+     *
+     * @param  obj the object to compare with
+     * @return {@code true} if the objects are the same;
+     *         {@code false} otherwise
+     * @see    #size()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof BitSet set))
+            return false;
+        if (this == obj)
+            return true;
+
+        checkInvariants();
+        set.checkInvariants();
+
+        if (wordsInUse != set.wordsInUse)
+            return false;
+
+        // Check words in use by both BitSets
+        for (int i = 0; i < wordsInUse; i++)
+            if (words[i] != set.words[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Cloning this {@code BitSet} produces a new {@code BitSet}
+     * that is equal to it.
+     * The clone of the bit set is another bit set that has exactly the
+     * same bits set to {@code true} as this bit set.
+     *
+     * @return a clone of this bit set
+     * @see    #size()
+     */
+    public Object clone() {
+        if (! sizeIsSticky)
+            trimToSize();
+
+        try {
+            BitSet result = (BitSet) super.clone();
+            result.words = words.clone();
+            result.checkInvariants();
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Attempts to reduce internal storage used for the bits in this bit set.
+     * Calling this method may, but is not required to, affect the value
+     * returned by a subsequent call to the {@link #size()} method.
+     */
+    private void trimToSize() {
+        if (wordsInUse != words.length) {
+            words = Arrays.copyOf(words, wordsInUse);
+            checkInvariants();
+        }
+    }
+
+    /**
+     * Save the state of the {@code BitSet} instance to a stream (i.e.,
+     * serialize it).
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream s)
+        throws IOException {
+
+        checkInvariants();
+
+        if (! sizeIsSticky)
+            trimToSize();
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("bits", words);
+        s.writeFields();
+    }
+
+    /**
+     * Reconstitute the {@code BitSet} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+        words = (long[]) fields.get("bits", null);
+
+        // Assume maximum length then find real length
+        // because recalculateWordsInUse assumes maintenance
+        // or reduction in logical size
+        wordsInUse = words.length;
+        recalculateWordsInUse();
+        sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic
+        checkInvariants();
+    }
+
+    /**
+     * Returns a string representation of this bit set. For every index
+     * for which this {@code BitSet} contains a bit in the set
+     * state, the decimal representation of that index is included in
+     * the result. Such indices are listed in order from lowest to
+     * highest, separated by ",&nbsp;" (a comma and a space) and
+     * surrounded by braces, resulting in the usual mathematical
+     * notation for a set of integers.
+     *
+     * <p>Example:
+     * <pre>
+     * BitSet drPepper = new BitSet();</pre>
+     * Now {@code drPepper.toString()} returns "{@code {}}".
+     * <pre>
+     * drPepper.set(2);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2}}".
+     * <pre>
+     * drPepper.set(4);
+     * drPepper.set(10);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}".
+     *
+     * @return a string representation of this bit set
+     */
+    public String toString() {
+        checkInvariants();
+
+        final int MAX_INITIAL_CAPACITY = Integer.MAX_VALUE - 8;
+        int numBits = (wordsInUse > 128) ?
+            cardinality() : wordsInUse * BITS_PER_WORD;
+        // Avoid overflow in the case of a humongous numBits
+        int initialCapacity = (numBits <= (MAX_INITIAL_CAPACITY - 2) / 6) ?
+            6 * numBits + 2 : MAX_INITIAL_CAPACITY;
+        StringBuilder b = new StringBuilder(initialCapacity);
+        b.append('{');
+
+        int i = nextSetBit(0);
+        if (i != -1) {
+            b.append(i);
+            while (true) {
+                if (++i < 0) break;
+                if ((i = nextSetBit(i)) < 0) break;
+                int endOfRun = nextClearBit(i);
+                do { b.append(", ").append(i); }
+                while (++i != endOfRun);
+            }
+        }
+
+        b.append('}');
+        return b.toString();
+    }
+
+    /**
+     * Returns a stream of indices for which this {@code BitSet}
+     * contains a bit in the set state. The indices are returned
+     * in order, from lowest to highest. The size of the stream
+     * is the number of bits in the set state, equal to the value
+     * returned by the {@link #cardinality()} method.
+     *
+     * <p>The stream binds to this bit set when the terminal stream operation
+     * commences (specifically, the spliterator for the stream is
+     * <a href="Spliterator.html#binding"><em>late-binding</em></a>).  If the
+     * bit set is modified during that operation then the result is undefined.
+     *
+     * @return a stream of integers representing set indices
+     * @since 1.8
+     */
+    public IntStream stream() {
+        class BitSetSpliterator implements Spliterator.OfInt {
+            private int index; // current bit index for a set bit
+            private int fence; // -1 until used; then one past last bit index
+            private int est;   // size estimate
+            private boolean root; // true if root and not split
+            // root == true then size estimate is accurate
+            // index == -1 or index >= fence if fully traversed
+            // Special case when the max bit set is Integer.MAX_VALUE
+
+            BitSetSpliterator(int origin, int fence, int est, boolean root) {
+                this.index = origin;
+                this.fence = fence;
+                this.est = est;
+                this.root = root;
+            }
+
+            private int getFence() {
+                int hi;
+                if ((hi = fence) < 0) {
+                    // Round up fence to maximum cardinality for allocated words
+                    // This is sufficient and cheap for sequential access
+                    // When splitting this value is lowered
+                    hi = fence = (wordsInUse >= wordIndex(Integer.MAX_VALUE))
+                                 ? Integer.MAX_VALUE
+                                 : wordsInUse << ADDRESS_BITS_PER_WORD;
+                    est = cardinality();
+                    index = nextSetBit(0);
+                }
+                return hi;
+            }
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                int hi = getFence();
+                int i = index;
+                if (i < 0 || i >= hi) {
+                    // Check if there is a final bit set for Integer.MAX_VALUE
+                    if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) {
+                        index = -1;
+                        action.accept(Integer.MAX_VALUE);
+                        return true;
+                    }
+                    return false;
+                }
+
+                index = nextSetBit(i + 1, wordIndex(hi - 1));
+                action.accept(i);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                int hi = getFence();
+                int i = index;
+                index = -1;
+
+                if (i >= 0 && i < hi) {
+                    action.accept(i++);
+
+                    int u = wordIndex(i);      // next lower word bound
+                    int v = wordIndex(hi - 1); // upper word bound
+
+                    words_loop:
+                    for (; u <= v && i <= hi; u++, i = u << ADDRESS_BITS_PER_WORD) {
+                        long word = words[u] & (WORD_MASK << i);
+                        while (word != 0) {
+                            i = (u << ADDRESS_BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+                            if (i >= hi) {
+                                // Break out of outer loop to ensure check of
+                                // Integer.MAX_VALUE bit set
+                                break words_loop;
+                            }
+
+                            // Flip the set bit
+                            word &= ~(1L << i);
+
+                            action.accept(i);
+                        }
+                    }
+                }
+
+                // Check if there is a final bit set for Integer.MAX_VALUE
+                if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) {
+                    action.accept(Integer.MAX_VALUE);
+                }
+            }
+
+            @Override
+            public OfInt trySplit() {
+                int hi = getFence();
+                int lo = index;
+                if (lo < 0) {
+                    return null;
+                }
+
+                // Lower the fence to be the upper bound of last bit set
+                // The index is the first bit set, thus this spliterator
+                // covers one bit and cannot be split, or two or more
+                // bits
+                hi = fence = (hi < Integer.MAX_VALUE || !get(Integer.MAX_VALUE))
+                        ? previousSetBit(hi - 1) + 1
+                        : Integer.MAX_VALUE;
+
+                // Find the mid point
+                int mid = (lo + hi) >>> 1;
+                if (lo >= mid) {
+                    return null;
+                }
+
+                // Raise the index of this spliterator to be the next set bit
+                // from the mid point
+                index = nextSetBit(mid, wordIndex(hi - 1));
+                root = false;
+
+                // Don't lower the fence (mid point) of the returned spliterator,
+                // traversal or further splitting will do that work
+                return new BitSetSpliterator(lo, mid, est >>>= 1, false);
+            }
+
+            @Override
+            public long estimateSize() {
+                getFence(); // force init
+                return est;
+            }
+
+            @Override
+            public int characteristics() {
+                // Only sized when root and not split
+                return (root ? Spliterator.SIZED : 0) |
+                    Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED;
+            }
+
+            @Override
+            public Comparator<? super Integer> getComparator() {
+                return null;
+            }
+        }
+        return StreamSupport.intStream(new BitSetSpliterator(0, -1, 0, true), false);
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code true}
+     * that occurs on or after the specified starting index and up to and
+     * including the specified word index
+     * If no such bit exists then {@code -1} is returned.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @param  toWordIndex the last word index to check (inclusive)
+     * @return the index of the next set bit, or {@code -1} if there
+     *         is no such bit
+     */
+    private int nextSetBit(int fromIndex, int toWordIndex) {
+        int u = wordIndex(fromIndex);
+        // Check if out of bounds
+        if (u > toWordIndex)
+            return -1;
+
+        long word = words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            // Check if out of bounds
+            if (++u > toWordIndex)
+                return -1;
+            word = words[u];
+        }
+    }
+
+}
diff --git a/android-35/java/util/Calendar.java b/android-35/java/util/Calendar.java
new file mode 100644
index 0000000..00fb182
--- /dev/null
+++ b/android-35/java/util/Calendar.java
@@ -0,0 +1,3708 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.AccessControlContext;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.time.Instant;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import libcore.icu.ICU;
+import libcore.icu.LocaleData;
+import sun.util.locale.provider.CalendarDataUtility;
+
+// Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
+// Android-changed: Support the "fw" extension since Android 13.
+/**
+ * The {@code Calendar} class is an abstract class that provides methods
+ * for converting between a specific instant in time and a set of {@link
+ * #fields calendar fields} such as {@code YEAR}, {@code MONTH},
+ * {@code DAY_OF_MONTH}, {@code HOUR}, and so on, and for
+ * manipulating the calendar fields, such as getting the date of the next
+ * week. An instant in time can be represented by a millisecond value that is
+ * an offset from the <a id="Epoch"><em>Epoch</em></a>, January 1, 1970
+ * 00:00:00.000 GMT (Gregorian).
+ *
+ * <p>The class also provides additional fields and methods for
+ * implementing a concrete calendar system outside the package. Those
+ * fields and methods are defined as {@code protected}.
+ *
+ * <p>
+ * Like other locale-sensitive classes, {@code Calendar} provides a
+ * class method, {@code getInstance}, for getting a generally useful
+ * object of this type. {@code Calendar}'s {@code getInstance} method
+ * returns a {@code Calendar} object whose
+ * calendar fields have been initialized with the current date and time:
+ * <blockquote>
+ * <pre>
+ *     Calendar rightNow = Calendar.getInstance();
+ * </pre>
+ * </blockquote>
+ *
+ * <p>A {@code Calendar} object can produce all the calendar field values
+ * needed to implement the date-time formatting for a particular language and
+ * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
+ * {@code Calendar} defines the range of values returned by
+ * certain calendar fields, as well as their meaning.  For example,
+ * the first month of the calendar system has value <code>MONTH ==
+ * JANUARY</code> for all calendars.  Other values are defined by the
+ * concrete subclass, such as {@code ERA}.  See individual field
+ * documentation and subclass documentation for details.
+ *
+ * <h2>Getting and Setting Calendar Field Values</h2>
+ *
+ * <p>The calendar field values can be set by calling the {@code set}
+ * methods. Any field values set in a {@code Calendar} will not be
+ * interpreted until it needs to calculate its time value (milliseconds from
+ * the Epoch) or values of the calendar fields. Calling the
+ * {@code get}, {@code getTimeInMillis}, {@code getTime},
+ * {@code add} and {@code roll} involves such calculation.
+ *
+ * <h3>Leniency</h3>
+ *
+ * <p>{@code Calendar} has two modes for interpreting the calendar
+ * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
+ * {@code Calendar} is in lenient mode, it accepts a wider range of
+ * calendar field values than it produces.  When a {@code Calendar}
+ * recomputes calendar field values for return by {@code get()}, all of
+ * the calendar fields are normalized. For example, a lenient
+ * {@code GregorianCalendar} interprets {@code MONTH == JANUARY},
+ * {@code DAY_OF_MONTH == 32} as February 1.
+ *
+ * <p>When a {@code Calendar} is in non-lenient mode, it throws an
+ * exception if there is any inconsistency in its calendar fields. For
+ * example, a {@code GregorianCalendar} always produces
+ * {@code DAY_OF_MONTH} values between 1 and the length of the month. A
+ * non-lenient {@code GregorianCalendar} throws an exception upon
+ * calculating its time or calendar field values if any out-of-range field
+ * value has been set.
+ *
+ * <h3><a id="first_week">First Week</a></h3>
+ *
+ * {@code Calendar} defines a locale-specific seven day week using two
+ * parameters: the first day of the week and the minimal days in first week
+ * (from 1 to 7).  These numbers are taken from the locale resource data or the
+ * locale itself when a {@code Calendar} is constructed. If the designated
+ * locale contains "fw" <a href="./Locale.html#def_locale_extension">
+ * Unicode extensions</a>, the first day of the week will be obtained according to
+ * those extensions.
+ * They may also be specified explicitly through the methods for setting their
+ * values.
+ *
+ * <p>When setting or getting the {@code WEEK_OF_MONTH} or
+ * {@code WEEK_OF_YEAR} fields, {@code Calendar} must determine the
+ * first week of the month or year as a reference point.  The first week of a
+ * month or year is defined as the earliest seven day period beginning on
+ * {@code getFirstDayOfWeek()} and containing at least
+ * {@code getMinimalDaysInFirstWeek()} days of that month or year.  Weeks
+ * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
+ * it.  Note that the normalized numbering returned by {@code get()} may be
+ * different.  For example, a specific {@code Calendar} subclass may
+ * designate the week before week 1 of a year as week <code><i>n</i></code> of
+ * the previous year.
+ *
+ * <h3>Calendar Fields Resolution</h3>
+ *
+ * When computing a date and time from the calendar fields, there
+ * may be insufficient information for the computation (such as only
+ * year and month with no day of month), or there may be inconsistent
+ * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
+ * 1996 is actually a Monday). {@code Calendar} will resolve
+ * calendar field values to determine the date and time in the
+ * following way.
+ *
+ * <p><a id="resolution">If there is any conflict in calendar field values,
+ * {@code Calendar} gives priorities to calendar fields that have been set
+ * more recently.</a> The following are the default combinations of the
+ * calendar fields. The most recent combination, as determined by the
+ * most recently set single field, will be used.
+ *
+ * <p><a id="date_resolution">For the date fields</a>:
+ * <blockquote>
+ * <pre>
+ * YEAR + MONTH + DAY_OF_MONTH
+ * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ * YEAR + DAY_OF_YEAR
+ * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
+ * </pre></blockquote>
+ *
+ * <a id="time_resolution">For the time of day fields</a>:
+ * <blockquote>
+ * <pre>
+ * HOUR_OF_DAY
+ * AM_PM + HOUR
+ * </pre></blockquote>
+ *
+ * <p>If there are any calendar fields whose values haven't been set in the selected
+ * field combination, {@code Calendar} uses their default values. The default
+ * value of each field may vary by concrete calendar systems. For example, in
+ * {@code GregorianCalendar}, the default of a field is the same as that
+ * of the start of the Epoch: i.e., {@code YEAR = 1970}, <code>MONTH =
+ * JANUARY</code>, {@code DAY_OF_MONTH = 1}, etc.
+ *
+ * <p>
+ * <strong>Note:</strong> There are certain possible ambiguities in
+ * interpretation of certain singular times, which are resolved in the
+ * following ways:
+ * <ol>
+ *     <li> 23:59 is the last minute of the day and 00:00 is the first
+ *          minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
+ *          Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
+ *
+ *     <li> Although historically not precise, midnight also belongs to "am",
+ *          and noon belongs to "pm", so on the same day,
+ *          12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
+ * </ol>
+ *
+ * <p>
+ * The date or time format strings are not part of the definition of a
+ * calendar, as those must be modifiable or overridable by the user at
+ * runtime. Use {@link DateFormat}
+ * to format dates.
+ *
+ * <h3>Field Manipulation</h3>
+ *
+ * The calendar fields can be changed using three methods:
+ * {@code set()}, {@code add()}, and {@code roll()}.
+ *
+ * <p><strong>{@code set(f, value)}</strong> changes calendar field
+ * {@code f} to {@code value}.  In addition, it sets an
+ * internal member variable to indicate that calendar field {@code f} has
+ * been changed. Although calendar field {@code f} is changed immediately,
+ * the calendar's time value in milliseconds is not recomputed until the next call to
+ * {@code get()}, {@code getTime()}, {@code getTimeInMillis()},
+ * {@code add()}, or {@code roll()} is made. Thus, multiple calls to
+ * {@code set()} do not trigger multiple, unnecessary
+ * computations. As a result of changing a calendar field using
+ * {@code set()}, other calendar fields may also change, depending on the
+ * calendar field, the calendar field value, and the calendar system. In addition,
+ * {@code get(f)} will not necessarily return {@code value} set by
+ * the call to the {@code set} method
+ * after the calendar fields have been recomputed. The specifics are determined by
+ * the concrete calendar class.</p>
+ *
+ * <p><em>Example</em>: Consider a {@code GregorianCalendar}
+ * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
+ * Calendar.SEPTEMBER)</code> sets the date to September 31,
+ * 1999. This is a temporary internal representation that resolves to
+ * October 1, 1999 if {@code getTime()} is then called. However, a
+ * call to {@code set(Calendar.DAY_OF_MONTH, 30)} before the call to
+ * {@code getTime()} sets the date to September 30, 1999, since
+ * no recomputation occurs after {@code set()} itself.</p>
+ *
+ * <p><strong>{@code add(f, delta)}</strong> adds {@code delta}
+ * to field {@code f}.  This is equivalent to calling <code>set(f,
+ * get(f) + delta)</code> with two adjustments:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Add rule 1</strong>. The value of field {@code f}
+ *   after the call minus the value of field {@code f} before the
+ *   call is {@code delta}, modulo any overflow that has occurred in
+ *   field {@code f}. Overflow occurs when a field value exceeds its
+ *   range and, as a result, the next larger field is incremented or
+ *   decremented and the field value is adjusted back into its range.</p>
+ *
+ *   <p><strong>Add rule 2</strong>. If a smaller field is expected to be
+ *   invariant, but it is impossible for it to be equal to its
+ *   prior value because of changes in its minimum or maximum after field
+ *   {@code f} is changed or other constraints, such as time zone
+ *   offset changes, then its value is adjusted to be as close
+ *   as possible to its expected value. A smaller field represents a
+ *   smaller unit of time. {@code HOUR} is a smaller field than
+ *   {@code DAY_OF_MONTH}. No adjustment is made to smaller fields
+ *   that are not expected to be invariant. The calendar system
+ *   determines what fields are expected to be invariant.</p>
+ * </blockquote>
+ *
+ * <p>In addition, unlike {@code set()}, {@code add()} forces
+ * an immediate recomputation of the calendar's milliseconds and all
+ * fields.</p>
+ *
+ * <p><em>Example</em>: Consider a {@code GregorianCalendar}
+ * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
+ * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
+ * 1</strong> sets the {@code MONTH} field to September, since
+ * adding 13 months to August gives September of the next year. Since
+ * {@code DAY_OF_MONTH} cannot be 31 in September in a
+ * {@code GregorianCalendar}, <strong>add rule 2</strong> sets the
+ * {@code DAY_OF_MONTH} to 30, the closest possible value. Although
+ * it is a smaller field, {@code DAY_OF_WEEK} is not adjusted by
+ * rule 2, since it is expected to change when the month changes in a
+ * {@code GregorianCalendar}.</p>
+ *
+ * <p><strong>{@code roll(f, delta)}</strong> adds
+ * {@code delta} to field {@code f} without changing larger
+ * fields. This is equivalent to calling {@code add(f, delta)} with
+ * the following adjustment:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Roll rule</strong>. Larger fields are unchanged after the
+ *   call. A larger field represents a larger unit of
+ *   time. {@code DAY_OF_MONTH} is a larger field than
+ *   {@code HOUR}.</p>
+ * </blockquote>
+ *
+ * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
+ *
+ * <p><strong>Usage model</strong>. To motivate the behavior of
+ * {@code add()} and {@code roll()}, consider a user interface
+ * component with increment and decrement buttons for the month, day, and
+ * year, and an underlying {@code GregorianCalendar}. If the
+ * interface reads January 31, 1999 and the user presses the month
+ * increment button, what should it read? If the underlying
+ * implementation uses {@code set()}, it might read March 3, 1999. A
+ * better result would be February 28, 1999. Furthermore, if the user
+ * presses the month increment button again, it should read March 31,
+ * 1999, not March 28, 1999. By saving the original date and using either
+ * {@code add()} or {@code roll()}, depending on whether larger
+ * fields should be affected, the user interface can behave as most users
+ * will intuitively expect.</p>
+ *
+ * @see          java.lang.System#currentTimeMillis()
+ * @see          Date
+ * @see          GregorianCalendar
+ * @see          TimeZone
+ * @see          java.text.DateFormat
+ * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since 1.1
+ */
+public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
+
+    // Data flow in Calendar
+    // ---------------------
+
+    // The current time is represented in two ways by Calendar: as UTC
+    // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
+    // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
+    // millis from the fields, and vice versa.  The data needed to do this
+    // conversion is encapsulated by a TimeZone object owned by the Calendar.
+    // The data provided by the TimeZone object may also be overridden if the
+    // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
+    // keeps track of what information was most recently set by the caller, and
+    // uses that to compute any other information as needed.
+
+    // If the user sets the fields using set(), the data flow is as follows.
+    // This is implemented by the Calendar subclass's computeTime() method.
+    // During this process, certain fields may be ignored.  The disambiguation
+    // algorithm for resolving which fields to pay attention to is described
+    // in the class documentation.
+
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
+    //           V
+    //   UTC millis (in time data member)
+
+    // If the user sets the UTC millis using setTime() or setTimeInMillis(),
+    // the data flow is as follows.  This is implemented by the Calendar
+    // subclass's computeFields() method.
+
+    //   UTC millis (in time data member)
+    //           |
+    //           | Using TimeZone getOffset()
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+
+    // In general, a round trip from fields, through local and UTC millis, and
+    // back out to fields is made when necessary.  This is implemented by the
+    // complete() method.  Resolving a partial set of fields into a UTC millis
+    // value allows all remaining fields to be generated from that value.  If
+    // the Calendar is lenient, the fields are also renormalized to standard
+    // ranges when they are regenerated.
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
+     * value; see subclass documentation.
+     *
+     * @see GregorianCalendar#AD
+     * @see GregorianCalendar#BC
+     */
+    public static final int ERA = 0;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * year. This is a calendar-specific value; see subclass documentation.
+     */
+    public static final int YEAR = 1;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * month. This is a calendar-specific value. The first month of
+     * the year in the Gregorian and Julian calendars is
+     * {@code JANUARY} which is 0; the last depends on the number
+     * of months in a year.
+     *
+     * @see #JANUARY
+     * @see #FEBRUARY
+     * @see #MARCH
+     * @see #APRIL
+     * @see #MAY
+     * @see #JUNE
+     * @see #JULY
+     * @see #AUGUST
+     * @see #SEPTEMBER
+     * @see #OCTOBER
+     * @see #NOVEMBER
+     * @see #DECEMBER
+     * @see #UNDECIMBER
+     */
+    public static final int MONTH = 2;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * week number within the current year.  The first week of the year, as
+     * defined by {@code getFirstDayOfWeek()} and
+     * {@code getMinimalDaysInFirstWeek()}, has value 1.  Subclasses define
+     * the value of {@code WEEK_OF_YEAR} for days before the first week of
+     * the year.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public static final int WEEK_OF_YEAR = 3;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * week number within the current month.  The first week of the month, as
+     * defined by {@code getFirstDayOfWeek()} and
+     * {@code getMinimalDaysInFirstWeek()}, has value 1.  Subclasses define
+     * the value of {@code WEEK_OF_MONTH} for days before the first week of
+     * the month.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public static final int WEEK_OF_MONTH = 4;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * day of the month. This is a synonym for {@code DAY_OF_MONTH}.
+     * The first day of the month has value 1.
+     *
+     * @see #DAY_OF_MONTH
+     */
+    public static final int DATE = 5;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * day of the month. This is a synonym for {@code DATE}.
+     * The first day of the month has value 1.
+     *
+     * @see #DATE
+     */
+    public static final int DAY_OF_MONTH = 5;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the day
+     * number within the current year.  The first day of the year has value 1.
+     */
+    public static final int DAY_OF_YEAR = 6;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the day
+     * of the week.  This field takes values {@code SUNDAY},
+     * {@code MONDAY}, {@code TUESDAY}, {@code WEDNESDAY},
+     * {@code THURSDAY}, {@code FRIDAY}, and {@code SATURDAY}.
+     *
+     * @see #SUNDAY
+     * @see #MONDAY
+     * @see #TUESDAY
+     * @see #WEDNESDAY
+     * @see #THURSDAY
+     * @see #FRIDAY
+     * @see #SATURDAY
+     */
+    public static final int DAY_OF_WEEK = 7;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * ordinal number of the day of the week within the current month. Together
+     * with the {@code DAY_OF_WEEK} field, this uniquely specifies a day
+     * within a month.  Unlike {@code WEEK_OF_MONTH} and
+     * {@code WEEK_OF_YEAR}, this field's value does <em>not</em> depend on
+     * {@code getFirstDayOfWeek()} or
+     * {@code getMinimalDaysInFirstWeek()}.  {@code DAY_OF_MONTH 1}
+     * through {@code 7} always correspond to <code>DAY_OF_WEEK_IN_MONTH
+     * 1</code>; {@code 8} through {@code 14} correspond to
+     * {@code DAY_OF_WEEK_IN_MONTH 2}, and so on.
+     * {@code DAY_OF_WEEK_IN_MONTH 0} indicates the week before
+     * {@code DAY_OF_WEEK_IN_MONTH 1}.  Negative values count back from the
+     * end of the month, so the last Sunday of a month is specified as
+     * {@code DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1}.  Because
+     * negative values count backward they will usually be aligned differently
+     * within the month than positive values.  For example, if a month has 31
+     * days, {@code DAY_OF_WEEK_IN_MONTH -1} will overlap
+     * {@code DAY_OF_WEEK_IN_MONTH 5} and the end of {@code 4}.
+     *
+     * @see #DAY_OF_WEEK
+     * @see #WEEK_OF_MONTH
+     */
+    public static final int DAY_OF_WEEK_IN_MONTH = 8;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating
+     * whether the {@code HOUR} is before or after noon.
+     * E.g., at 10:04:15.250 PM the {@code AM_PM} is {@code PM}.
+     *
+     * @see #AM
+     * @see #PM
+     * @see #HOUR
+     */
+    public static final int AM_PM = 9;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * hour of the morning or afternoon. {@code HOUR} is used for the
+     * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
+     * E.g., at 10:04:15.250 PM the {@code HOUR} is 10.
+     *
+     * @see #AM_PM
+     * @see #HOUR_OF_DAY
+     */
+    public static final int HOUR = 10;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * hour of the day. {@code HOUR_OF_DAY} is used for the 24-hour clock.
+     * E.g., at 10:04:15.250 PM the {@code HOUR_OF_DAY} is 22.
+     *
+     * @see #HOUR
+     */
+    public static final int HOUR_OF_DAY = 11;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * minute within the hour.
+     * E.g., at 10:04:15.250 PM the {@code MINUTE} is 4.
+     */
+    public static final int MINUTE = 12;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * second within the minute.
+     * E.g., at 10:04:15.250 PM the {@code SECOND} is 15.
+     */
+    public static final int SECOND = 13;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * millisecond within the second.
+     * E.g., at 10:04:15.250 PM the {@code MILLISECOND} is 250.
+     */
+    public static final int MILLISECOND = 14;
+
+    /**
+     * Field number for {@code get} and {@code set}
+     * indicating the raw offset from GMT in milliseconds.
+     * <p>
+     * This field reflects the correct GMT offset value of the time
+     * zone of this {@code Calendar} if the
+     * {@code TimeZone} implementation subclass supports
+     * historical GMT offset changes.
+     */
+    public static final int ZONE_OFFSET = 15;
+
+    /**
+     * Field number for {@code get} and {@code set} indicating the
+     * daylight saving offset in milliseconds.
+     * <p>
+     * This field reflects the correct daylight saving offset value of
+     * the time zone of this {@code Calendar} if the
+     * {@code TimeZone} implementation subclass supports
+     * historical Daylight Saving Time schedule changes.
+     */
+    public static final int DST_OFFSET = 16;
+
+    /**
+     * The number of distinct fields recognized by {@code get} and {@code set}.
+     * Field numbers range from {@code 0..FIELD_COUNT-1}.
+     */
+    public static final int FIELD_COUNT = 17;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Sunday.
+     */
+    public static final int SUNDAY = 1;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Monday.
+     */
+    public static final int MONDAY = 2;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Tuesday.
+     */
+    public static final int TUESDAY = 3;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Wednesday.
+     */
+    public static final int WEDNESDAY = 4;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Thursday.
+     */
+    public static final int THURSDAY = 5;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Friday.
+     */
+    public static final int FRIDAY = 6;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Saturday.
+     */
+    public static final int SATURDAY = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * first month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int JANUARY = 0;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * second month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int FEBRUARY = 1;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * third month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int MARCH = 2;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fourth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int APRIL = 3;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fifth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int MAY = 4;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * sixth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int JUNE = 5;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * seventh month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int JULY = 6;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eighth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int AUGUST = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * ninth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int SEPTEMBER = 8;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * tenth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int OCTOBER = 9;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eleventh month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int NOVEMBER = 10;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * twelfth month of the year in the Gregorian and Julian calendars.
+     */
+    public static final int DECEMBER = 11;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * thirteenth month of the year. Although {@code GregorianCalendar}
+     * does not use this value, lunar calendars do.
+     */
+    public static final int UNDECIMBER = 12;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from midnight to just before noon.
+     */
+    public static final int AM = 0;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from noon to just before midnight.
+     */
+    public static final int PM = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating names in all styles, such as
+     * "January" and "Jan".
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int ALL_STYLES = 0;
+
+    static final int STANDALONE_MASK = 0x8000;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #SHORT_FORMAT}.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int SHORT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #LONG_FORMAT}.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @since 1.6
+     */
+    public static final int LONG = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name used for format. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @since 1.8
+     */
+    public static final int NARROW_FORMAT = 4;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name independently. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int NARROW_STANDALONE = NARROW_FORMAT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used for format.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_FORMAT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used for format.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_FORMAT = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used independently,
+     * such as a month abbreviation as calendar headers.
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used independently,
+     * such as a month name as calendar headers.
+     *
+     * @see #LONG_FORMAT
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_STANDALONE = LONG | STANDALONE_MASK;
+
+    // Internal notes:
+    // Calendar contains two kinds of time representations: current "time" in
+    // milliseconds, and a set of calendar "fields" representing the current time.
+    // The two representations are usually in sync, but can get out of sync
+    // as follows.
+    // 1. Initially, no fields are set, and the time is invalid.
+    // 2. If the time is set, all fields are computed and in sync.
+    // 3. If a single field is set, the time is invalid.
+    // Recomputation of the time and fields happens when the object needs
+    // to return a result to the user, or use a result for a computation.
+
+    /**
+     * The calendar field values for the currently set time for this calendar.
+     * This is an array of {@code FIELD_COUNT} integers, with index values
+     * {@code ERA} through {@code DST_OFFSET}.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected int           fields[];
+
+    /**
+     * The flags which tell if a specified calendar field for the calendar is set.
+     * A new object has no fields set.  After the first call to a method
+     * which generates the fields, they all remain set after that.
+     * This is an array of {@code FIELD_COUNT} booleans, with index values
+     * {@code ERA} through {@code DST_OFFSET}.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isSet[];
+
+    /**
+     * Pseudo-time-stamps which specify when each field was set. There
+     * are two special values, UNSET and COMPUTED. Values from
+     * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
+     */
+    private transient int   stamp[];
+
+    /**
+     * The currently set time for this calendar, expressed in milliseconds after
+     * January 1, 1970, 0:00:00 GMT.
+     * @see #isTimeSet
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected long          time;
+
+    /**
+     * True if then the value of {@code time} is valid.
+     * The time is made invalid by a change to an item of {@code field[]}.
+     * @see #time
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isTimeSet;
+
+    /**
+     * True if {@code fields[]} are in sync with the currently set time.
+     * If false, then the next attempt to get the value of a field will
+     * force a recomputation of all fields from the current value of
+     * {@code time}.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       areFieldsSet;
+
+    /**
+     * True if all fields have been set.
+     * @serial
+     */
+    transient boolean       areAllFieldsSet;
+
+    /**
+     * {@code True} if this calendar allows out-of-range field values during computation
+     * of {@code time} from {@code fields[]}.
+     * @see #setLenient
+     * @see #isLenient
+     * @serial
+     */
+    private boolean         lenient = true;
+
+    /**
+     * The {@code TimeZone} used by this calendar. {@code Calendar}
+     * uses the time zone data to translate between locale and GMT time.
+     * @serial
+     */
+    private TimeZone        zone;
+
+    /**
+     * {@code True} if zone references to a shared TimeZone object.
+     */
+    private transient boolean sharedZone = false;
+
+    /**
+     * The first day of the week, with possible values {@code SUNDAY},
+     * {@code MONDAY}, etc.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             firstDayOfWeek;
+
+    /**
+     * The number of days required for the first week in a month or year,
+     * with possible values from 1 to 7.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             minimalDaysInFirstWeek;
+
+    /**
+     * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
+     * of a Locale.
+     */
+    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
+        = new ConcurrentHashMap<>(3);
+
+    // Special values of stamp[]
+    /**
+     * The corresponding fields[] has no value.
+     */
+    private static final int        UNSET = 0;
+
+    /**
+     * The value of the corresponding fields[] has been calculated internally.
+     */
+    private static final int        COMPUTED = 1;
+
+    /**
+     * The value of the corresponding fields[] has been set externally. Stamp
+     * values which are greater than 1 represents the (pseudo) time when the
+     * corresponding fields[] value was set.
+     */
+    private static final int        MINIMUM_USER_STAMP = 2;
+
+    /**
+     * The mask value that represents all of the fields.
+     */
+    static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
+
+    /**
+     * The next available value for {@code stamp[]}, an internal array.
+     * This actually should not be written out to the stream, and will probably
+     * be removed from the stream in the near future.  In the meantime,
+     * a value of {@code MINIMUM_USER_STAMP} should be used.
+     * @serial
+     */
+    private int             nextStamp = MINIMUM_USER_STAMP;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.5
+    // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
+    //     as well as compatible values for other fields.  This is a
+    //     transitional format.
+    // - 2 (not implemented yet) a future version, in which fields[],
+    //     areFieldsSet, and isTimeSet become transient, and isSet[] is
+    //     removed. In JDK 1.1.6 we write a format compatible with version 2.
+    static final int        currentSerialVersion = 1;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.5 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.6 or later.  Writes a correct 'time' value
+     * as well as compatible values for other fields.  This is a
+     * transitional format.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable {@code serialVersionOnStream}
+     * is written.
+     * @serial
+     * @since 1.1.6
+     */
+    private int             serialVersionOnStream = currentSerialVersion;
+
+    // Proclaim serialization compatibility with JDK 1.1
+    @java.io.Serial
+    static final long       serialVersionUID = -1807547505821590642L;
+
+    // Mask values for calendar fields
+    @SuppressWarnings("PointlessBitwiseExpression")
+    static final int ERA_MASK           = (1 << ERA);
+    static final int YEAR_MASK          = (1 << YEAR);
+    static final int MONTH_MASK         = (1 << MONTH);
+    static final int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
+    static final int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
+    static final int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
+    static final int DATE_MASK          = DAY_OF_MONTH_MASK;
+    static final int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
+    static final int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
+    static final int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
+    static final int AM_PM_MASK         = (1 << AM_PM);
+    static final int HOUR_MASK          = (1 << HOUR);
+    static final int HOUR_OF_DAY_MASK   = (1 << HOUR_OF_DAY);
+    static final int MINUTE_MASK        = (1 << MINUTE);
+    static final int SECOND_MASK        = (1 << SECOND);
+    static final int MILLISECOND_MASK   = (1 << MILLISECOND);
+    static final int ZONE_OFFSET_MASK   = (1 << ZONE_OFFSET);
+    static final int DST_OFFSET_MASK    = (1 << DST_OFFSET);
+
+    /**
+     * {@code Calendar.Builder} is used for creating a {@code Calendar} from
+     * various date-time parameters.
+     *
+     * <p>There are two ways to set a {@code Calendar} to a date-time value. One
+     * is to set the instant parameter to a millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>. The other is to set individual
+     * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired
+     * values. These two ways can't be mixed. Trying to set both the instant and
+     * individual fields will cause an {@link IllegalStateException} to be
+     * thrown. However, it is permitted to override previous values of the
+     * instant or field parameters.
+     *
+     * <p>If no enough field parameters are given for determining date and/or
+     * time, calendar specific default values are used when building a
+     * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value
+     * isn't given for the Gregorian calendar, 1970 will be used. If there are
+     * any conflicts among field parameters, the <a
+     * href="Calendar.html#resolution"> resolution rules</a> are applied.
+     * Therefore, the order of field setting matters.
+     *
+     * <p>In addition to the date-time parameters,
+     * the {@linkplain #setLocale(Locale) locale},
+     * {@linkplain #setTimeZone(TimeZone) time zone},
+     * {@linkplain #setWeekDefinition(int, int) week definition}, and
+     * {@linkplain #setLenient(boolean) leniency mode} parameters can be set.
+     *
+     * <p><b>Examples</b>
+     * <p>The following are sample usages. Sample code assumes that the
+     * {@code Calendar} constants are statically imported.
+     *
+     * <p>The following code produces a {@code Calendar} with date 2012-12-31
+     * (Gregorian) because Monday is the first day of a week with the <a
+     * href="GregorianCalendar.html#iso8601_compatible_setting"> ISO 8601
+     * compatible week parameters</a>.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
+     *                        .setWeekDate(2013, 1, MONDAY).build();</pre>
+     * <p>The following code produces a Japanese {@code Calendar} with date
+     * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA}
+     * is <em>Heisei</em> that started on that day.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
+     *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();</pre>
+     *
+     * @since 1.8
+     * @see Calendar#getInstance(TimeZone, Locale)
+     * @see Calendar#fields
+     */
+    public static class Builder {
+        private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
+        private static final int WEEK_YEAR = FIELD_COUNT;
+
+        private long instant;
+        // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined
+        private int[] fields;
+        // Pseudo timestamp starting from MINIMUM_USER_STAMP.
+        // (COMPUTED is used to indicate that the instant has been set.)
+        private int nextStamp;
+        // maxFieldIndex keeps the max index of fields which have been set.
+        // (WEEK_YEAR is never included.)
+        private int maxFieldIndex;
+        private String type;
+        private TimeZone zone;
+        private boolean lenient = true;
+        private Locale locale;
+        private int firstDayOfWeek, minimalDaysInFirstWeek;
+
+        /**
+         * Constructs a {@code Calendar.Builder}.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the instant parameter to the given {@code instant} value that is
+         * a millisecond offset from <a href="Calendar.html#Epoch">the
+         * Epoch</a>.
+         *
+         * @param instant a millisecond offset from the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(long instant) {
+            if (fields != null) {
+                throw new IllegalStateException();
+            }
+            this.instant = instant;
+            nextStamp = COMPUTED;
+            return this;
+        }
+
+        /**
+         * Sets the instant parameter to the {@code instant} value given by a
+         * {@link Date}. This method is equivalent to a call to
+         * {@link #setInstant(long) setInstant(instant.getTime())}.
+         *
+         * @param instant a {@code Date} representing a millisecond offset from
+         *                the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException  if {@code instant} is {@code null}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(Date instant) {
+            return setInstant(instant.getTime()); // NPE if instant == null
+        }
+
+        /**
+         * Sets the {@code field} parameter to the given {@code value}.
+         * {@code field} is an index to the {@link Calendar#fields}, such as
+         * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is
+         * not performed in this method. Any out of range values are either
+         * normalized in lenient mode or detected as an invalid value in
+         * non-lenient mode when building a {@code Calendar}.
+         *
+         * @param field an index to the {@code Calendar} fields
+         * @param value the field value
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code field} is invalid
+         * @throws IllegalStateException if the instant value has already been set,
+         *                      or if fields have been set too many
+         *                      (approximately {@link Integer#MAX_VALUE}) times.
+         * @see Calendar#set(int, int)
+         */
+        public Builder set(int field, int value) {
+            // Note: WEEK_YEAR can't be set with this method.
+            if (field < 0 || field >= FIELD_COUNT) {
+                throw new IllegalArgumentException("field is invalid");
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            allocateFields();
+            internalSet(field, value);
+            return this;
+        }
+
+        // Android-changed: fix typo in example code.
+        /**
+         * Sets field parameters to their values given by
+         * {@code fieldValuePairs} that are pairs of a field and its value.
+         * For example,
+         * <pre>
+         *   setFields(Calendar.YEAR, 2013,
+         *             Calendar.MONTH, Calendar.DECEMBER,
+         *             Calendar.DAY_OF_MONTH, 23);</pre>
+         * is equivalent to the sequence of the following
+         * {@link #set(int, int) set} calls:
+         * <pre>
+         *   set(Calendar.YEAR, 2013)
+         *   .set(Calendar.MONTH, Calendar.DECEMBER)
+         *   .set(Calendar.DAY_OF_MONTH, 23);</pre>
+         *
+         * @param fieldValuePairs field-value pairs
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code fieldValuePairs} is {@code null}
+         * @throws IllegalArgumentException if any of fields are invalid,
+         *             or if {@code fieldValuePairs.length} is an odd number.
+         * @throws IllegalStateException    if the instant value has been set,
+         *             or if fields have been set too many (approximately
+         *             {@link Integer#MAX_VALUE}) times.
+         */
+        public Builder setFields(int... fieldValuePairs) {
+            int len = fieldValuePairs.length;
+            if ((len % 2) != 0) {
+                throw new IllegalArgumentException();
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            if ((nextStamp + len / 2) < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            allocateFields();
+            for (int i = 0; i < len; ) {
+                int field = fieldValuePairs[i++];
+                // Note: WEEK_YEAR can't be set with this method.
+                if (field < 0 || field >= FIELD_COUNT) {
+                    throw new IllegalArgumentException("field is invalid");
+                }
+                internalSet(field, fieldValuePairs[i++]);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the date field parameters to the values given by {@code year},
+         * {@code month}, and {@code dayOfMonth}. This method is equivalent to
+         * a call to:
+         * <pre>
+         *   setFields(Calendar.YEAR, year,
+         *             Calendar.MONTH, month,
+         *             Calendar.DAY_OF_MONTH, dayOfMonth);</pre>
+         *
+         * @param year       the {@link Calendar#YEAR YEAR} value
+         * @param month      the {@link Calendar#MONTH MONTH} value
+         *                   (the month numbering is <em>0-based</em>).
+         * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setDate(int year, int month, int dayOfMonth) {
+            return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, and {@code second}. This method is
+         * equivalent to a call to:
+         * <pre>
+         *   setTimeOfDay(hourOfDay, minute, second, 0);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second) {
+            return setTimeOfDay(hourOfDay, minute, second, 0);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, {@code second}, and
+         * {@code millis}. This method is equivalent to a call to:
+         * <pre>
+         *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
+         *             Calendar.MINUTE, minute,
+         *             Calendar.SECOND, second,
+         *             Calendar.MILLISECOND, millis);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @param millis    the {@link Calendar#MILLISECOND MILLISECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) {
+            return setFields(HOUR_OF_DAY, hourOfDay, MINUTE, minute,
+                             SECOND, second, MILLISECOND, millis);
+        }
+
+        /**
+         * Sets the week-based date parameters to the values with the given
+         * date specifiers - week year, week of year, and day of week.
+         *
+         * <p>If the specified calendar doesn't support week dates, the
+         * {@link #build() build} method will throw an {@link IllegalArgumentException}.
+         *
+         * @param weekYear   the week year
+         * @param weekOfYear the week number based on {@code weekYear}
+         * @param dayOfWeek  the day of week value: one of the constants
+         *     for the {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} field:
+         *     {@link Calendar#SUNDAY SUNDAY}, ..., {@link Calendar#SATURDAY SATURDAY}.
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setWeekDate(int, int, int)
+         * @see Calendar#isWeekDateSupported()
+         */
+        public Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+            allocateFields();
+            internalSet(WEEK_YEAR, weekYear);
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(DAY_OF_WEEK, dayOfWeek);
+            return this;
+        }
+
+        /**
+         * Sets the time zone parameter to the given {@code zone}. If no time
+         * zone parameter is given to this {@code Calendar.Builder}, the
+         * {@linkplain TimeZone#getDefault() default
+         * {@code TimeZone}} will be used in the {@link #build() build}
+         * method.
+         *
+         * @param zone the {@link TimeZone}
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code zone} is {@code null}
+         * @see Calendar#setTimeZone(TimeZone)
+         */
+        public Builder setTimeZone(TimeZone zone) {
+            if (zone == null) {
+                throw new NullPointerException();
+            }
+            this.zone = zone;
+            return this;
+        }
+
+        /**
+         * Sets the lenient mode parameter to the value given by {@code lenient}.
+         * If no lenient parameter is given to this {@code Calendar.Builder},
+         * lenient mode will be used in the {@link #build() build} method.
+         *
+         * @param lenient {@code true} for lenient mode;
+         *                {@code false} for non-lenient mode
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setLenient(boolean)
+         */
+        public Builder setLenient(boolean lenient) {
+            this.lenient = lenient;
+            return this;
+        }
+
+        /**
+         * Sets the calendar type parameter to the given {@code type}. The
+         * calendar type given by this method has precedence over any explicit
+         * or implicit calendar type given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * <p>In addition to the available calendar types returned by the
+         * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes}
+         * method, {@code "gregorian"} and {@code "iso8601"} as aliases of
+         * {@code "gregory"} can be used with this method.
+         *
+         * @param type the calendar type
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code type} is {@code null}
+         * @throws IllegalArgumentException if {@code type} is unknown
+         * @throws IllegalStateException if another calendar type has already been set
+         * @see Calendar#getCalendarType()
+         * @see Calendar#getAvailableCalendarTypes()
+         */
+        public Builder setCalendarType(String type) {
+            if (type.equals("gregorian")) { // NPE if type == null
+                type = "gregory";
+            }
+            if (!Calendar.getAvailableCalendarTypes().contains(type)
+                    && !type.equals("iso8601")) {
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            if (this.type == null) {
+                this.type = type;
+            } else {
+                if (!this.type.equals(type)) {
+                    throw new IllegalStateException("calendar type override");
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the locale parameter to the given {@code locale}. If no locale
+         * is given to this {@code Calendar.Builder}, the {@linkplain
+         * Locale#getDefault(Locale.Category) default {@code Locale}}
+         * for {@link Locale.Category#FORMAT} will be used.
+         *
+         * <p>If no calendar type is explicitly given by a call to the
+         * {@link #setCalendarType(String) setCalendarType} method,
+         * the {@code Locale} value is used to determine what type of
+         * {@code Calendar} to be built.
+         *
+         * <p>If no week definition parameters are explicitly given by a call to
+         * the {@link #setWeekDefinition(int,int) setWeekDefinition} method, the
+         * {@code Locale}'s default values are used.
+         *
+         * @param locale the {@link Locale}
+         * @throws NullPointerException if {@code locale} is {@code null}
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#getInstance(Locale)
+         */
+        public Builder setLocale(Locale locale) {
+            if (locale == null) {
+                throw new NullPointerException();
+            }
+            this.locale = locale;
+            return this;
+        }
+
+        /**
+         * Sets the week definition parameters to the values given by
+         * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
+         * used to determine the <a href="Calendar.html#first_week">first
+         * week</a> of a year. The parameters given by this method have
+         * precedence over the default values given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * @param firstDayOfWeek the first day of a week; one of
+         *                       {@link Calendar#SUNDAY} to {@link Calendar#SATURDAY}
+         * @param minimalDaysInFirstWeek the minimal number of days in the first
+         *                               week (1..7)
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code firstDayOfWeek} or
+         *                                  {@code minimalDaysInFirstWeek} is invalid
+         * @see Calendar#getFirstDayOfWeek()
+         * @see Calendar#getMinimalDaysInFirstWeek()
+         */
+        public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) {
+            if (!isValidWeekParameter(firstDayOfWeek)
+                    || !isValidWeekParameter(minimalDaysInFirstWeek)) {
+                throw new IllegalArgumentException();
+            }
+            this.firstDayOfWeek = firstDayOfWeek;
+            this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
+            return this;
+        }
+
+        // Android-changed: Support the "tz" extension since Android 13.
+        /**
+         * Returns a {@code Calendar} built from the parameters set by the
+         * setter methods. The calendar type given by the {@link #setCalendarType(String)
+         * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is
+         * used to determine what {@code Calendar} to be created. If no explicit
+         * calendar type is given, the locale's default calendar is created.
+         *
+         * <p>If the calendar type is {@code "iso8601"}, the
+         * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date}
+         * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)}
+         * to be the <em>proleptic</em> Gregorian calendar. Its week definition
+         * parameters are also set to be <a
+         * href="GregorianCalendar.html#iso8601_compatible_setting">compatible
+         * with the ISO 8601 standard</a>. Note that the
+         * {@link GregorianCalendar#getCalendarType() getCalendarType} method of
+         * a {@code GregorianCalendar} created with {@code "iso8601"} returns
+         * {@code "gregory"}.
+         *
+         * <p>The default values are used for locale and time zone if these
+         * parameters haven't been given explicitly.
+         * <p>
+         * Since Android 13, if the locale contains the time zone with "tz"
+         * <a href="Locale.html#def_locale_extension">Unicode extension</a>,
+         * and time zone hasn't been given explicitly, time zone in the locale
+         * is used.
+         *
+         * <p>Any out of range field values are either normalized in lenient
+         * mode or detected as an invalid value in non-lenient mode.
+         *
+         * @return a {@code Calendar} built with parameters of this {@code
+         *         Calendar.Builder}
+         * @throws IllegalArgumentException if the calendar type is unknown, or
+         *             if any invalid field values are given in non-lenient mode, or
+         *             if a week date is given for the calendar type that doesn't
+         *             support week dates.
+         * @see Calendar#getInstance(TimeZone, Locale)
+         * @see Locale#getDefault(Locale.Category)
+         * @see TimeZone#getDefault()
+         */
+        public Calendar build() {
+            if (locale == null) {
+                locale = Locale.getDefault();
+            }
+            if (zone == null) {
+                zone = defaultTimeZone(locale);
+            }
+            if (type == null) {
+                type = locale.getUnicodeLocaleType("ca");
+            }
+            if (type == null) {
+                // BEGIN Android-changed: don't switch to buddhist calendar based on locale.
+                // See http://b/35138741
+                /*
+                if (locale.getCountry() == "TH"
+                        && locale.getLanguage() == "th") {
+                    type = "buddhist";
+                } else {
+                    type = "gregory";
+                }
+                */
+                type = "gregory";
+                // END Android-changed: don't switch to buddhist calendar based on locale.
+            }
+            final Calendar cal = switch (type) {
+                case "gregory" -> new GregorianCalendar(zone, locale, true);
+                case "iso8601" -> {
+                    GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
+                    // make gcal a proleptic Gregorian
+                    gcal.setGregorianChange(new Date(Long.MIN_VALUE));
+                    // and week definition to be compatible with ISO 8601
+                    setWeekDefinition(MONDAY, 4);
+                    yield gcal;
+                }
+                // BEGIN Android-changed: removed support for "buddhist" and "japanese".
+                /*
+                case "buddhist" -> {
+                    var buddhistCalendar = new BuddhistCalendar(zone, locale);
+                    buddhistCalendar.clear();
+                    yield buddhistCalendar;
+                }
+                case "japanese" -> new JapaneseImperialCalendar(zone, locale, true);
+                */
+                // END Android-changed: removed support for "buddhist" and "japanese".
+                default -> throw new IllegalArgumentException("unknown calendar type: " + type);
+            };
+            cal.setLenient(lenient);
+            if (firstDayOfWeek != 0) {
+                cal.setFirstDayOfWeek(firstDayOfWeek);
+                cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+            }
+            if (isInstantSet()) {
+                cal.setTimeInMillis(instant);
+                cal.complete();
+                return cal;
+            }
+
+            if (fields != null) {
+                boolean weekDate = isSet(WEEK_YEAR)
+                                       && fields[WEEK_YEAR] > fields[YEAR];
+                if (weekDate && !cal.isWeekDateSupported()) {
+                    throw new IllegalArgumentException("week date is unsupported by " + type);
+                }
+
+                // Set the fields from the min stamp to the max stamp so that
+                // the fields resolution works in the Calendar.
+                for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
+                    for (int index = 0; index <= maxFieldIndex; index++) {
+                        if (fields[index] == stamp) {
+                            cal.set(index, fields[NFIELDS + index]);
+                            break;
+                        }
+                    }
+                }
+
+                if (weekDate) {
+                    int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
+                    int dayOfWeek = isSet(DAY_OF_WEEK)
+                                    ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
+                    cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
+                }
+                cal.complete();
+            }
+
+            return cal;
+        }
+
+        private void allocateFields() {
+            if (fields == null) {
+                fields = new int[NFIELDS * 2];
+                nextStamp = MINIMUM_USER_STAMP;
+                maxFieldIndex = -1;
+            }
+        }
+
+        private void internalSet(int field, int value) {
+            fields[field] = nextStamp++;
+            if (nextStamp < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            fields[NFIELDS + field] = value;
+            if (field > maxFieldIndex && field < WEEK_YEAR) {
+                maxFieldIndex = field;
+            }
+        }
+
+        private boolean isInstantSet() {
+            return nextStamp == COMPUTED;
+        }
+
+        private boolean isSet(int index) {
+            return fields != null && fields[index] > UNSET;
+        }
+
+        private boolean isValidWeekParameter(int value) {
+            return value > 0 && value <= 7;
+        }
+    }
+
+    /**
+     * Constructs a Calendar with the default time zone
+     * and the default {@link java.util.Locale.Category#FORMAT FORMAT}
+     * locale.
+     * @see     TimeZone#getDefault
+     */
+    protected Calendar()
+    {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        sharedZone = true;
+    }
+
+    /**
+     * Constructs a calendar with the specified time zone and locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     */
+    protected Calendar(TimeZone zone, Locale aLocale)
+    {
+        // BEGIN Android-added: Allow aLocale == null.
+        // http://b/16938922.
+        //
+        // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+        // here. We should add a targetSdkVersion based check and throw for this case.
+        if (aLocale == null) {
+            aLocale = Locale.getDefault();
+        }
+        // END Android-added: Allow aLocale == null.
+        fields = new int[FIELD_COUNT];
+        isSet = new boolean[FIELD_COUNT];
+        stamp = new int[FIELD_COUNT];
+
+        this.zone = zone;
+        setWeekCountData(aLocale);
+    }
+
+    // Android-changed: Support the "tz" extension since Android 13.
+    /**
+     * Gets a calendar using the default time zone and locale. The
+     * {@code Calendar} returned is based on the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     * <p>
+     * Since Android 13, if the locale contains the time zone with "tz"
+     * <a href="Locale.html#def_locale_extension">Unicode extension</a>,
+     * that time zone is used instead.
+     *
+     * @return a Calendar.
+     */
+    public static Calendar getInstance()
+    {
+        Locale aLocale = Locale.getDefault(Locale.Category.FORMAT);
+        return createCalendar(defaultTimeZone(aLocale), aLocale);
+    }
+
+    /**
+     * Gets a calendar using the specified time zone and default locale.
+     * The {@code Calendar} returned is based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the time zone to use
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone)
+    {
+        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    // Android-changed: Support the "tz" extension since Android 13.
+    /**
+     * Gets a calendar using the default time zone and specified locale.
+     * The {@code Calendar} returned is based on the current time
+     * in the default time zone with the given locale.
+     * <p>
+     * Since Android 13, if the locale contains the time zone with "tz"
+     * <a href="Locale.html#def_locale_extension">Unicode extension</a>,
+     * that time zone is used instead.
+     *
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(Locale aLocale)
+    {
+        return createCalendar(defaultTimeZone(aLocale), aLocale);
+    }
+
+    /**
+     * Gets a calendar with the specified time zone and locale.
+     * The {@code Calendar} returned is based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone,
+                                       Locale aLocale)
+    {
+        return createCalendar(zone, aLocale);
+    }
+
+    // BEGIN Android-added: add getJapaneseImperialInstance().
+    /**
+     * Create a Japanese Imperial Calendar.
+     * @hide
+     */
+    public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
+        return new JapaneseImperialCalendar(zone, aLocale);
+    }
+    // END Android-added: add getJapaneseImperialInstance().
+
+    private static TimeZone defaultTimeZone(Locale l) {
+        TimeZone defaultTZ = TimeZone.getDefault();
+        // Android-added: Accept null locale. http://b/16938922
+        if (l == null) {
+            return defaultTZ;
+        }
+        String shortTZID = l.getUnicodeLocaleType("tz");
+        return shortTZID != null ?
+            // Android-changed: Use ICU to convert LDML short ID
+            // TimeZoneNameUtility.convertLDMLShortID(shortTZID)
+            Optional.ofNullable(ICU.convertToTzId(shortTZID))
+                .map(TimeZone::getTimeZone)
+                .orElse(defaultTZ) :
+            defaultTZ;
+    }
+
+    private static Calendar createCalendar(TimeZone zone,
+                                           Locale aLocale)
+    {
+        // BEGIN Android-changed: only support GregorianCalendar here.
+        /*
+        CalendarProvider provider =
+            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
+                                 .getCalendarProvider();
+        if (provider != null) {
+            try {
+                return provider.getInstance(zone, aLocale);
+            } catch (IllegalArgumentException iae) {
+                // fall back to the default instantiation
+            }
+        }
+
+        Calendar cal = null;
+
+        if (aLocale.hasExtensions()) {
+            String caltype = aLocale.getUnicodeLocaleType("ca");
+            if (caltype != null) {
+                cal = switch (caltype) {
+                    case "buddhist" -> new BuddhistCalendar(zone, aLocale);
+                    case "japanese" -> new JapaneseImperialCalendar(zone, aLocale);
+                    case "gregory"  -> new GregorianCalendar(zone, aLocale);
+                    default         -> null;
+                };
+            }
+        }
+        if (cal == null) {
+            // If no known calendar type is explicitly specified,
+            // perform the traditional way to create a Calendar:
+            // create a BuddhistCalendar for th_TH locale,
+            // a JapaneseImperialCalendar for ja_JP_JP locale, or
+            // a GregorianCalendar for any other locales.
+            // NOTE: The language, country and variant strings are interned.
+            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
+                cal = new BuddhistCalendar(zone, aLocale);
+            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
+                       && aLocale.getCountry() == "JP") {
+                cal = new JapaneseImperialCalendar(zone, aLocale);
+            } else {
+                cal = new GregorianCalendar(zone, aLocale);
+            }
+        }
+        return cal;
+        */
+        return new GregorianCalendar(zone, aLocale);
+        // END Android-changed: only support GregorianCalendar here.
+    }
+
+    /**
+     * Returns an array of all locales for which the {@code getInstance}
+     * methods of this class can return localized instances.
+     * The array returned must contain at least a {@code Locale}
+     * instance equal to {@link java.util.Locale#US Locale.US}.
+     *
+     * @return An array of locales for which localized
+     *         {@code Calendar} instances are available.
+     */
+    public static synchronized Locale[] getAvailableLocales()
+    {
+        return DateFormat.getAvailableLocales();
+    }
+
+    /**
+     * Converts the current calendar field values in {@link #fields fields[]}
+     * to the millisecond time value
+     * {@link #time}.
+     *
+     * @see #complete()
+     * @see #computeFields()
+     */
+    protected abstract void computeTime();
+
+    /**
+     * Converts the current millisecond time value {@link #time}
+     * to calendar field values in {@link #fields fields[]}.
+     * This allows you to sync up the calendar field values with
+     * a new time that is set for the calendar.  The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * {@link #complete()} method.
+     *
+     * @see #computeTime()
+     */
+    protected abstract void computeFields();
+
+    /**
+     * Returns a {@code Date} object representing this
+     * {@code Calendar}'s time value (millisecond offset from the <a
+     * href="#Epoch">Epoch</a>").
+     *
+     * @return a {@code Date} representing the time value.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public final Date getTime() {
+        return new Date(getTimeInMillis());
+    }
+
+    /**
+     * Sets this Calendar's time with the given {@code Date}.
+     * <p>
+     * Note: Calling {@code setTime()} with
+     * {@code Date(Long.MAX_VALUE)} or {@code Date(Long.MIN_VALUE)}
+     * may yield incorrect field values from {@code get()}.
+     *
+     * @param date the given Date.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     * @throws NullPointerException if {@code date} is {@code null}
+     */
+    public final void setTime(Date date) {
+        Objects.requireNonNull(date, "date must not be null");
+        setTimeInMillis(date.getTime());
+    }
+
+    /**
+     * Returns this Calendar's time value in milliseconds.
+     *
+     * @return the current time as UTC milliseconds from the epoch.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     */
+    public long getTimeInMillis() {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        return time;
+    }
+
+    /**
+     * Sets this Calendar's current time from the given long value.
+     *
+     * @param millis the new time in UTC milliseconds from the epoch.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public void setTimeInMillis(long millis) {
+        // If we don't need to recalculate the calendar field values,
+        // do nothing.
+// BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+//        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
+//            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
+        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
+// END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+
+            return;
+        }
+        time = millis;
+        isTimeSet = true;
+        areFieldsSet = false;
+        computeFields();
+        areAllFieldsSet = areFieldsSet = true;
+    }
+
+    /**
+     * Returns the value of the given calendar field. In lenient mode,
+     * all calendar fields are normalized. In non-lenient mode, all
+     * calendar fields are validated and this method throws an
+     * exception if any calendar fields have out-of-range values. The
+     * normalization and validation are handled by the
+     * {@link #complete()} method, which process is calendar
+     * system dependent.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #set(int,int)
+     * @see #complete()
+     */
+    public int get(int field)
+    {
+        complete();
+        return internalGet(field);
+    }
+
+    /**
+     * Returns the value of the given calendar field. This method does
+     * not involve normalization or validation of the field value.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @see #get(int)
+     */
+    protected final int internalGet(int field)
+    {
+        return fields[field];
+    }
+
+    /**
+     * Sets the value of the given calendar field. This method does
+     * not affect any setting state of the field in this
+     * {@code Calendar} instance.
+     *
+     * @throws IndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #areFieldsSet
+     * @see #isTimeSet
+     * @see #areAllFieldsSet
+     * @see #set(int,int)
+     */
+    final void internalSet(int field, int value)
+    {
+        fields[field] = value;
+    }
+
+    /**
+     * Sets the given calendar field to the given value. The value is not
+     * interpreted by this method regardless of the leniency mode.
+     *
+     * @param field the given calendar field.
+     * @param value the value to be set for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * in non-lenient mode.
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     * @see #get(int)
+     */
+    public void set(int field, int value)
+    {
+        // If the fields are partially normalized, calculate all the
+        // fields before changing any fields.
+        if (areFieldsSet && !areAllFieldsSet) {
+            computeFields();
+        }
+        internalSet(field, value);
+        isTimeSet = false;
+        areFieldsSet = false;
+        isSet[field] = true;
+        stamp[field] = nextStamp++;
+        if (nextStamp == Integer.MAX_VALUE) {
+            adjustStamp();
+        }
+    }
+
+    /**
+     * Sets the values for the calendar fields {@code YEAR},
+     * {@code MONTH}, and {@code DAY_OF_MONTH}.
+     * Previous values of other calendar fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field.
+     * @param month the value used to set the {@code MONTH} calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+    }
+
+    /**
+     * Sets the values for the calendar fields {@code YEAR},
+     * {@code MONTH}, {@code DAY_OF_MONTH},
+     * {@code HOUR_OF_DAY}, and {@code MINUTE}.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field.
+     * @param month the value used to set the {@code MONTH} calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
+     * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field.
+     * @param minute the value used to set the {@code MINUTE} calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+    }
+
+    /**
+     * Sets the values for the fields {@code YEAR}, {@code MONTH},
+     * {@code DAY_OF_MONTH}, {@code HOUR_OF_DAY}, {@code MINUTE}, and
+     * {@code SECOND}.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field.
+     * @param month the value used to set the {@code MONTH} calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
+     * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field.
+     * @param minute the value used to set the {@code MINUTE} calendar field.
+     * @param second the value used to set the {@code SECOND} calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute,
+                          int second)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+        set(SECOND, second);
+    }
+
+    /**
+     * Sets all the calendar field values and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this {@code Calendar} undefined. This means that {@link
+     * #isSet(int) isSet()} will return {@code false} for all the
+     * calendar fields, and the date and time calculations will treat
+     * the fields as if they had never been set. A
+     * {@code Calendar} implementation class may use its specific
+     * default field values for date/time calculations. For example,
+     * {@code GregorianCalendar} uses 1970 if the
+     * {@code YEAR} field value is undefined.
+     *
+     * @see #clear(int)
+     */
+    public final void clear()
+    {
+        for (int i = 0; i < fields.length; ) {
+            stamp[i] = fields[i] = 0; // UNSET == 0
+            isSet[i++] = false;
+        }
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Sets the given calendar field value and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this {@code Calendar} undefined. This means that {@link
+     * #isSet(int) isSet(field)} will return {@code false}, and
+     * the date and time calculations will treat the field as if it
+     * had never been set. A {@code Calendar} implementation
+     * class may use the field's specific default value for date and
+     * time calculations.
+     *
+     * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
+     * fields are handled independently and the <a
+     * href="#time_resolution">the resolution rule for the time of
+     * day</a> is applied. Clearing one of the fields doesn't reset
+     * the hour of day value of this {@code Calendar}. Use {@link
+     * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
+     * value.
+     *
+     * @param field the calendar field to be cleared.
+     * @see #clear()
+     */
+    public final void clear(int field)
+    {
+        fields[field] = 0;
+        stamp[field] = UNSET;
+        isSet[field] = false;
+
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Determines if the given calendar field has a value set,
+     * including cases that the value has been set by internal fields
+     * calculations triggered by a {@code get} method call.
+     *
+     * @param field the calendar field to test
+     * @return {@code true} if the given calendar field has a value set;
+     * {@code false} otherwise.
+     */
+    public final boolean isSet(int field)
+    {
+        return stamp[field] != UNSET;
+    }
+
+    /**
+     * Returns the string representation of the calendar
+     * {@code field} value in the given {@code style} and
+     * {@code locale}.  If no string representation is
+     * applicable, {@code null} is returned. This method calls
+     * {@link Calendar#get(int) get(field)} to get the calendar
+     * {@code field} value if the string representation is
+     * applicable to the given calendar {@code field}.
+     *
+     * <p>For example, if this {@code Calendar} is a
+     * {@code GregorianCalendar} and its date is 2005-01-01, then
+     * the string representation of the {@link #MONTH} field would be
+     * "January" in the long style in an English locale or "Jan" in
+     * the short style. However, no string representation would be
+     * available for the {@link #DAY_OF_MONTH} field, and this method
+     * would return {@code null}.
+     *
+     * <p>The default implementation supports the calendar fields for
+     * which a {@link DateFormatSymbols} has names in the given
+     * {@code locale}.
+     *
+     * @param field
+     *        the calendar field for which the string representation
+     *        is returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}.
+     * @param locale
+     *        the locale for the string representation
+     *        (any calendar types specified by {@code locale} are ignored)
+     * @return the string representation of the given
+     *        {@code field} in the given {@code style}, or
+     *        {@code null} if no string representation is
+     *        applicable.
+     * @throws    IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @throws    NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public String getDisplayName(int field, int style, Locale locale) {
+        // BEGIN Android-changed: Treat ALL_STYLES as SHORT.
+        // Android has traditionally treated ALL_STYLES as SHORT, even though
+        // it's not documented to be a valid value for style.
+        if (style == ALL_STYLES) {
+            style = SHORT;
+        }
+        // END Android-changed: Treat ALL_STYLES as SHORT.
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                            ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        String calendarType = getCalendarType();
+        int fieldValue = get(field);
+        // the standalone/narrow styles and short era are supported only through
+        // CalendarNameProviders.
+        if (isStandaloneStyle(style) || isNarrowFormatStyle(style) ||
+            field == ERA && (style & SHORT) == SHORT) {
+            String val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                    field, fieldValue,
+                                                                    style, locale);
+            // Perform fallback here to follow the CLDR rules
+            if (val == null) {
+                if (isNarrowFormatStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     toStandaloneStyle(style),
+                                                                     locale);
+                } else if (isStandaloneStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     getBaseStyle(style),
+                                                                     locale);
+                }
+            }
+            return val;
+        }
+
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            if (fieldValue < strings.length) {
+                return strings[fieldValue];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a {@code Map} containing all names of the calendar
+     * {@code field} in the given {@code style} and
+     * {@code locale} and their corresponding field values. For
+     * example, if this {@code Calendar} is a {@link
+     * GregorianCalendar}, the returned map would contain "Jan" to
+     * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
+     * {@linkplain #SHORT short} style in an English locale.
+     *
+     * <p>Narrow names may not be unique due to use of single characters,
+     * such as "S" for Sunday and Saturday. In that case narrow names are not
+     * included in the returned {@code Map}.
+     *
+     * <p>The values of other calendar fields may be taken into
+     * account to determine a set of display names. For example, if
+     * this {@code Calendar} is a lunisolar calendar system and
+     * the year value given by the {@link #YEAR} field has a leap
+     * month, this method would return month names containing the leap
+     * month name, and month names are mapped to their values specific
+     * for the year.
+     *
+     * <p>The default implementation supports display names contained in
+     * a {@link DateFormatSymbols}. For example, if {@code field}
+     * is {@link #MONTH} and {@code style} is {@link
+     * #ALL_STYLES}, this method returns a {@code Map} containing
+     * all strings returned by {@link DateFormatSymbols#getShortMonths()}
+     * and {@link DateFormatSymbols#getMonths()}.
+     *
+     * @param field
+     *        the calendar field for which the display names are returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}
+     * @param locale
+     *        the locale for the display names
+     * @return a {@code Map} containing all display names in
+     *        {@code style} and {@code locale} and their
+     *        field values, or {@code null} if no display names
+     *        are defined for {@code field}
+     * @throws    IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @throws    NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        // Android-added: Add complete() here to fix leniency. http://b/35382060
+        complete();
+
+        String calendarType = getCalendarType();
+        if (style == ALL_STYLES || isStandaloneStyle(style) || isNarrowFormatStyle(style) ||
+            field == ERA && (style & SHORT) == SHORT) {
+            Map<String, Integer> map;
+            map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field, style, locale);
+
+            // Perform fallback here to follow the CLDR rules
+            if (map == null) {
+                if (isNarrowFormatStyle(style)) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      toStandaloneStyle(style), locale);
+                } else if (style != ALL_STYLES) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      getBaseStyle(style), locale);
+                }
+            }
+            return map;
+        }
+
+        // SHORT or LONG
+        return getDisplayNamesImpl(field, style, locale);
+    }
+
+    private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            Map<String,Integer> names = new HashMap<>();
+            for (int i = 0; i < strings.length; i++) {
+                if (strings[i].isEmpty()) {
+                    continue;
+                }
+                names.put(strings[i], i);
+            }
+            return names;
+        }
+        return null;
+    }
+
+    boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
+                                   Locale locale, int fieldMask) {
+        int baseStyle = getBaseStyle(style); // Ignore the standalone mask
+        if (field < 0 || field >= fields.length ||
+            baseStyle < minStyle || baseStyle > maxStyle || baseStyle == 3) {
+            throw new IllegalArgumentException();
+        }
+        // BEGIN Android-added: Check for invalid baseStyle == 3.
+        // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
+        if (baseStyle == 3) {
+            throw new IllegalArgumentException();
+        }
+        // END Android-added: Check for invalid baseStyle == 3.
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        return isFieldSet(fieldMask, field);
+    }
+
+    private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
+        int baseStyle = getBaseStyle(style); // ignore the standalone mask
+
+        // DateFormatSymbols doesn't support any narrow names.
+        if (baseStyle == NARROW_FORMAT) {
+            return null;
+        }
+
+        return switch (field) {
+            case ERA         -> symbols.getEras();
+            case MONTH       -> (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
+            case DAY_OF_WEEK -> (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
+            case AM_PM       -> symbols.getAmPmStrings();
+            default -> null;
+        };
+    }
+
+    /**
+     * Fills in any unset fields in the calendar fields. First, the {@link
+     * #computeTime()} method is called if the time value (millisecond offset
+     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
+     * calendar field values. Then, the {@link #computeFields()} method is
+     * called to calculate all calendar field values.
+     */
+    protected void complete()
+    {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        if (!areFieldsSet || !areAllFieldsSet) {
+            computeFields(); // fills in unset fields
+            areAllFieldsSet = areFieldsSet = true;
+        }
+    }
+
+    /**
+     * Returns whether the value of the specified calendar field has been set
+     * externally by calling one of the setter methods rather than by the
+     * internal time calculation.
+     *
+     * @return {@code true} if the field has been set externally,
+     * {@code false} otherwise.
+     * @throws    IndexOutOfBoundsException if the specified
+     *                {@code field} is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #selectFields()
+     * @see #setFieldsComputed(int)
+     */
+    final boolean isExternallySet(int field) {
+        return stamp[field] >= MINIMUM_USER_STAMP;
+    }
+
+    /**
+     * Returns a field mask (bit mask) indicating all calendar fields that
+     * have the state of externally or internally set.
+     *
+     * @return a bit mask indicating set state fields
+     */
+    final int getSetStateFields() {
+        int mask = 0;
+        for (int i = 0; i < fields.length; i++) {
+            if (stamp[i] != UNSET) {
+                mask |= 1 << i;
+            }
+        }
+        return mask;
+    }
+
+    /**
+     * Sets the state of the specified calendar fields to
+     * <em>computed</em>. This state means that the specified calendar fields
+     * have valid values that have been set by internal time calculation
+     * rather than by calling one of the setter methods.
+     *
+     * @param fieldMask the field to be marked as computed.
+     * @throws    IndexOutOfBoundsException if the specified
+     *                {@code field} is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsComputed(int fieldMask) {
+        if (fieldMask == ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                stamp[i] = COMPUTED;
+                isSet[i] = true;
+            }
+            areFieldsSet = areAllFieldsSet = true;
+        } else {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 1) {
+                    stamp[i] = COMPUTED;
+                    isSet[i] = true;
+                } else {
+                    if (areAllFieldsSet && !isSet[i]) {
+                        areAllFieldsSet = false;
+                    }
+                }
+                fieldMask >>>= 1;
+            }
+        }
+    }
+
+    /**
+     * Sets the state of the calendar fields that are <em>not</em> specified
+     * by {@code fieldMask} to <em>unset</em>. If {@code fieldMask}
+     * specifies all the calendar fields, then the state of this
+     * {@code Calendar} becomes that all the calendar fields are in sync
+     * with the time value (millisecond offset from the Epoch).
+     *
+     * @param fieldMask the field mask indicating which calendar fields are in
+     * sync with the time value.
+     * @throws    IndexOutOfBoundsException if the specified
+     *                {@code field} is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsNormalized(int fieldMask) {
+        if (fieldMask != ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 0) {
+                    stamp[i] = fields[i] = 0; // UNSET == 0
+                    isSet[i] = false;
+                }
+                fieldMask >>= 1;
+            }
+        }
+
+        // Some or all of the fields are in sync with the
+        // milliseconds, but the stamp values are not normalized yet.
+        areFieldsSet = true;
+        areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the calendar fields are partially in sync with the time
+     * value or fully in sync but not stamp values are not normalized yet.
+     */
+    final boolean isPartiallyNormalized() {
+        return areFieldsSet && !areAllFieldsSet;
+    }
+
+    /**
+     * Returns whether the calendar fields are fully in sync with the time
+     * value.
+     */
+    final boolean isFullyNormalized() {
+        return areFieldsSet && areAllFieldsSet;
+    }
+
+    /**
+     * Marks this Calendar as not sync'd.
+     */
+    final void setUnnormalized() {
+        areFieldsSet = areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the specified {@code field} is on in the
+     * {@code fieldMask}.
+     */
+    static boolean isFieldSet(int fieldMask, int field) {
+        return (fieldMask & (1 << field)) != 0;
+    }
+
+    /**
+     * Returns a field mask indicating which calendar field values
+     * to be used to calculate the time value. The calendar fields are
+     * returned as a bit mask, each bit of which corresponds to a field, i.e.,
+     * the mask value of {@code field} is <code>(1 &lt;&lt;
+     * field)</code>. For example, 0x26 represents the {@code YEAR},
+     * {@code MONTH}, and {@code DAY_OF_MONTH} fields (i.e., 0x26 is
+     * equal to
+     * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
+     *
+     * <p>This method supports the calendar fields resolution as described in
+     * the class description. If the bit mask for a given field is on and its
+     * field has not been set (i.e., {@code isSet(field)} is
+     * {@code false}), then the default value of the field has to be
+     * used, which case means that the field has been selected because the
+     * selected combination involves the field.
+     *
+     * @return a bit mask of selected fields
+     * @see #isExternallySet(int)
+     */
+    final int selectFields() {
+        // This implementation has been taken from the GregorianCalendar class.
+
+        // The YEAR field must always be used regardless of its SET
+        // state because YEAR is a mandatory field to determine the date
+        // and the default value (EPOCH_YEAR) may change through the
+        // normalization process.
+        int fieldMask = YEAR_MASK;
+
+        if (stamp[ERA] != UNSET) {
+            fieldMask |= ERA_MASK;
+        }
+        // Find the most recent group of fields specifying the day within
+        // the year.  These may be any of the following combinations:
+        //   MONTH + DAY_OF_MONTH
+        //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+        //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+        //   DAY_OF_YEAR
+        //   WEEK_OF_YEAR + DAY_OF_WEEK
+        // We look for the most recent of the fields in each group to determine
+        // the age of the group.  For groups involving a week-related field such
+        // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
+        // week-related field and the DAY_OF_WEEK must be set for the group as a
+        // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
+        int dowStamp = stamp[DAY_OF_WEEK];
+        int monthStamp = stamp[MONTH];
+        int domStamp = stamp[DAY_OF_MONTH];
+        int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
+        int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+        int doyStamp = stamp[DAY_OF_YEAR];
+        int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
+
+        int bestStamp = domStamp;
+        if (womStamp > bestStamp) {
+            bestStamp = womStamp;
+        }
+        if (dowimStamp > bestStamp) {
+            bestStamp = dowimStamp;
+        }
+        if (doyStamp > bestStamp) {
+            bestStamp = doyStamp;
+        }
+        if (woyStamp > bestStamp) {
+            bestStamp = woyStamp;
+        }
+
+        /* No complete combination exists.  Look for WEEK_OF_MONTH,
+         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
+         * as DAY_OF_WEEK_IN_MONTH.
+         */
+        if (bestStamp == UNSET) {
+            womStamp = stamp[WEEK_OF_MONTH];
+            dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+            woyStamp = stamp[WEEK_OF_YEAR];
+            bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
+
+            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
+             * result in bestStamp = domStamp = UNSET if no fields are set,
+             * which indicates DAY_OF_MONTH.
+             */
+            if (bestStamp == UNSET) {
+                bestStamp = domStamp = monthStamp;
+            }
+        }
+
+        if (bestStamp == domStamp ||
+           (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
+           (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
+            fieldMask |= MONTH_MASK;
+            if (bestStamp == domStamp) {
+                fieldMask |= DAY_OF_MONTH_MASK;
+            } else {
+                assert (bestStamp == womStamp || bestStamp == dowimStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                if (womStamp == dowimStamp) {
+                    // When they are equal, give the priority to
+                    // WEEK_OF_MONTH for compatibility.
+                    if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                    }
+                } else {
+                    if (bestStamp == womStamp) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        assert (bestStamp == dowimStamp);
+                        if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
+                            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                        }
+                    }
+                }
+            }
+        } else {
+            assert (bestStamp == doyStamp || bestStamp == woyStamp ||
+                    bestStamp == UNSET);
+            if (bestStamp == doyStamp) {
+                fieldMask |= DAY_OF_YEAR_MASK;
+            } else {
+                assert (bestStamp == woyStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                fieldMask |= WEEK_OF_YEAR_MASK;
+            }
+        }
+
+        // Find the best set of fields specifying the time of day.  There
+        // are only two possibilities here; the HOUR_OF_DAY or the
+        // AM_PM and the HOUR.
+        int hourOfDayStamp = stamp[HOUR_OF_DAY];
+        int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
+        bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
+
+        // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
+        if (bestStamp == UNSET) {
+            bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
+        }
+
+        // Hours
+        if (bestStamp != UNSET) {
+            if (bestStamp == hourOfDayStamp) {
+                fieldMask |= HOUR_OF_DAY_MASK;
+            } else {
+                fieldMask |= HOUR_MASK;
+                if (stamp[AM_PM] != UNSET) {
+                    fieldMask |= AM_PM_MASK;
+                }
+            }
+        }
+        if (stamp[MINUTE] != UNSET) {
+            fieldMask |= MINUTE_MASK;
+        }
+        if (stamp[SECOND] != UNSET) {
+            fieldMask |= SECOND_MASK;
+        }
+        if (stamp[MILLISECOND] != UNSET) {
+            fieldMask |= MILLISECOND_MASK;
+        }
+        if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
+                fieldMask |= ZONE_OFFSET_MASK;
+        }
+        if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
+            fieldMask |= DST_OFFSET_MASK;
+        }
+
+        return fieldMask;
+    }
+
+    int getBaseStyle(int style) {
+        return style & ~STANDALONE_MASK;
+    }
+
+    // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat.
+    /**
+     * @hide
+     */
+    public static int toStandaloneStyle(int style) {
+    // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat.
+        return style | STANDALONE_MASK;
+    }
+
+    private boolean isStandaloneStyle(int style) {
+        return (style & STANDALONE_MASK) != 0;
+    }
+
+    private boolean isNarrowStyle(int style) {
+        return style == NARROW_FORMAT || style == NARROW_STANDALONE;
+    }
+
+    private boolean isNarrowFormatStyle(int style) {
+        return style == NARROW_FORMAT;
+    }
+
+    /**
+     * Returns the pseudo-time-stamp for two fields, given their
+     * individual pseudo-time-stamps.  If either of the fields
+     * is unset, then the aggregate is unset.  Otherwise, the
+     * aggregate is the later of the two stamps.
+     */
+    private static int aggregateStamp(int stamp_a, int stamp_b) {
+        if (stamp_a == UNSET || stamp_b == UNSET) {
+            return UNSET;
+        }
+        return (stamp_a > stamp_b) ? stamp_a : stamp_b;
+    }
+
+    /**
+     * Returns an unmodifiable {@code Set} containing all calendar types
+     * supported by {@code Calendar} in the runtime environment. The available
+     * calendar types can be used for the <a
+     * href="Locale.html#def_locale_extension">Unicode locale extensions</a>.
+     * The {@code Set} returned contains at least {@code "gregory"}. The
+     * calendar types don't include aliases, such as {@code "gregorian"} for
+     * {@code "gregory"}.
+     *
+     * @return an unmodifiable {@code Set} containing all available calendar types
+     * @since 1.8
+     * @see #getCalendarType()
+     * @see Calendar.Builder#setCalendarType(String)
+     * @see Locale#getUnicodeLocaleType(String)
+     */
+    public static Set<String> getAvailableCalendarTypes() {
+        return AvailableCalendarTypes.SET;
+    }
+
+    private static class AvailableCalendarTypes {
+        private static final Set<String> SET;
+        static {
+            Set<String> set = new HashSet<>(3);
+            set.add("gregory");
+            // Android-changed: removed "buddhist" and "japanese".
+            // set.add("buddhist");
+            // set.add("japanese");
+            SET = Collections.unmodifiableSet(set);
+        }
+        private AvailableCalendarTypes() {
+        }
+    }
+
+    /**
+     * Returns the calendar type of this {@code Calendar}. Calendar types are
+     * defined by the <em>Unicode Locale Data Markup Language (LDML)</em>
+     * specification.
+     *
+     * <p>The default implementation of this method returns the class name of
+     * this {@code Calendar} instance. Any subclasses that implement
+     * LDML-defined calendar systems should override this method to return
+     * appropriate calendar types.
+     *
+     * @return the LDML-defined calendar type or the class name of this
+     *         {@code Calendar} instance
+     * @since 1.8
+     * @see <a href="Locale.html#def_extensions">Locale extensions</a>
+     * @see Locale.Builder#setLocale(Locale)
+     * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
+     */
+    public String getCalendarType() {
+        return this.getClass().getName();
+    }
+
+    /**
+     * Compares this {@code Calendar} to the specified
+     * {@code Object}.  The result is {@code true} if and only if
+     * the argument is a {@code Calendar} object of the same calendar
+     * system that represents the same time value (millisecond offset from the
+     * <a href="#Epoch">Epoch</a>) under the same
+     * {@code Calendar} parameters as this object.
+     *
+     * <p>The {@code Calendar} parameters are the values represented
+     * by the {@code isLenient}, {@code getFirstDayOfWeek},
+     * {@code getMinimalDaysInFirstWeek} and {@code getTimeZone}
+     * methods. If there is any difference in those parameters
+     * between the two {@code Calendar}s, this method returns
+     * {@code false}.
+     *
+     * <p>Use the {@link #compareTo(Calendar) compareTo} method to
+     * compare only the time values.
+     *
+     * @param obj the object to compare with.
+     * @return {@code true} if this object is equal to {@code obj};
+     * {@code false} otherwise.
+     */
+    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        try {
+            Calendar that = (Calendar)obj;
+            return compareTo(getMillisOf(that)) == 0 &&
+                lenient == that.lenient &&
+                firstDayOfWeek == that.firstDayOfWeek &&
+                minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
+                // Android-changed: We have no sun.util.calendar.ZoneInfo. Use libcore.util.ZoneInfo
+                // (zone instanceof ZoneInfo ?
+                (zone instanceof libcore.util.ZoneInfo ?
+                    zone.equals(that.zone) :
+                    zone.equals(that.getTimeZone()));
+        } catch (Exception e) {
+            // Note: GregorianCalendar.computeTime throws
+            // IllegalArgumentException if the ERA value is invalid
+            // even it's in lenient mode.
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this calendar.
+     *
+     * @return a hash code value for this object.
+     * @since 1.2
+     */
+    @Override
+    public int hashCode() {
+        // 'otheritems' represents the hash code for the previous versions.
+        int otheritems = (lenient ? 1 : 0)
+            | (firstDayOfWeek << 1)
+            | (minimalDaysInFirstWeek << 4)
+            | (zone.hashCode() << 7);
+        long t = getMillisOf(this);
+        return (int) t ^ (int)(t >> 32) ^ otheritems;
+    }
+
+    /**
+     * Returns whether this {@code Calendar} represents a time
+     * before the time represented by the specified
+     * {@code Object}. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) < 0
+     * }</pre>
+     * if and only if {@code when} is a {@code Calendar}
+     * instance. Otherwise, the method returns {@code false}.
+     *
+     * @param when the {@code Object} to be compared
+     * @return {@code true} if the time of this
+     * {@code Calendar} is before the time represented by
+     * {@code when}; {@code false} otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean before(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) < 0;
+    }
+
+    /**
+     * Returns whether this {@code Calendar} represents a time
+     * after the time represented by the specified
+     * {@code Object}. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) > 0
+     * }</pre>
+     * if and only if {@code when} is a {@code Calendar}
+     * instance. Otherwise, the method returns {@code false}.
+     *
+     * @param when the {@code Object} to be compared
+     * @return {@code true} if the time of this {@code Calendar} is
+     * after the time represented by {@code when}; {@code false}
+     * otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean after(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) > 0;
+    }
+
+    /**
+     * Compares the time values (millisecond offsets from the <a
+     * href="#Epoch">Epoch</a>) represented by two
+     * {@code Calendar} objects.
+     *
+     * @param anotherCalendar the {@code Calendar} to be compared.
+     * @return the value {@code 0} if the time represented by the argument
+     * is equal to the time represented by this {@code Calendar}; a value
+     * less than {@code 0} if the time of this {@code Calendar} is
+     * before the time represented by the argument; and a value greater than
+     * {@code 0} if the time of this {@code Calendar} is after the
+     * time represented by the argument.
+     * @throws    NullPointerException if the specified {@code Calendar} is
+     *            {@code null}.
+     * @throws    IllegalArgumentException if the time value of the
+     * specified {@code Calendar} object can't be obtained due to
+     * any invalid calendar values.
+     * @since   1.5
+     */
+    @Override
+    public int compareTo(Calendar anotherCalendar) {
+        return compareTo(getMillisOf(anotherCalendar));
+    }
+
+    /**
+     * Adds or subtracts the specified amount of time to the given calendar field,
+     * based on the calendar's rules. For example, to subtract 5 days from
+     * the current time of the calendar, you can achieve it by calling:
+     * <p>{@code add(Calendar.DAY_OF_MONTH, -5)}.
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @see #roll(int,int)
+     * @see #set(int,int)
+     */
+    public abstract void add(int field, int amount);
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields. For example, to roll the current
+     * date up by one day, you can achieve it by calling:
+     * <p>roll(Calendar.DATE, true).
+     * When rolling on the year or Calendar.YEAR field, it will roll the year
+     * value in the range between 1 and the value returned by calling
+     * {@code getMaximum(Calendar.YEAR)}.
+     * When rolling on the month or Calendar.MONTH field, other fields like
+     * date might conflict and, need to be changed. For instance,
+     * rolling the month on the date 01/31/96 will result in 02/29/96.
+     * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
+     * roll the hour value in the range between 0 and 23, which is zero-based.
+     *
+     * @param field the time field.
+     * @param up indicates if the value of the specified time field is to be
+     * rolled up or rolled down. Use true if rolling up, false otherwise.
+     * @see Calendar#add(int,int)
+     * @see Calendar#set(int,int)
+     */
+    public abstract void roll(int field, boolean up);
+
+    /**
+     * Adds the specified (signed) amount to the specified calendar field
+     * without changing larger fields.  A negative amount means to roll
+     * down.
+     *
+     * <p>NOTE:  This default implementation on {@code Calendar} just repeatedly calls the
+     * version of {@link #roll(int,boolean) roll()} that rolls by one unit.  This may not
+     * always do the right thing.  For example, if the {@code DAY_OF_MONTH} field is 31,
+     * rolling through February will leave it set to 28.  The {@code GregorianCalendar}
+     * version of this function takes care of this problem.  Other subclasses
+     * should also provide overrides of this function that do the right thing.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to the calendar {@code field}.
+     * @since 1.2
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    public void roll(int field, int amount)
+    {
+        while (amount > 0) {
+            roll(field, true);
+            amount--;
+        }
+        while (amount < 0) {
+            roll(field, false);
+            amount++;
+        }
+    }
+
+    /**
+     * Sets the time zone with the given time zone value.
+     *
+     * @param value the given time zone.
+     */
+    public void setTimeZone(TimeZone value)
+    {
+        zone = value;
+        sharedZone = false;
+        /* Recompute the fields from the time using the new zone.  This also
+         * works if isTimeSet is false (after a call to set()).  In that case
+         * the time will be computed from the fields using the new zone, then
+         * the fields will get recomputed from that.  Consider the sequence of
+         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
+         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
+         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
+         * AFTER it up to the next call to complete().
+         */
+        areAllFieldsSet = areFieldsSet = false;
+    }
+
+    /**
+     * Gets the time zone.
+     *
+     * @return the time zone object associated with this calendar.
+     */
+    public TimeZone getTimeZone()
+    {
+        // If the TimeZone object is shared by other Calendar instances, then
+        // create a clone.
+        if (sharedZone) {
+            zone = (TimeZone) zone.clone();
+            sharedZone = false;
+        }
+        return zone;
+    }
+
+    /**
+     * Returns the time zone (without cloning).
+     */
+    TimeZone getZone() {
+        return zone;
+    }
+
+    /**
+     * Sets the sharedZone flag to {@code shared}.
+     */
+    void setZoneShared(boolean shared) {
+        sharedZone = shared;
+    }
+
+    /**
+     * Specifies whether or not date/time interpretation is to be lenient.  With
+     * lenient interpretation, a date such as "February 942, 1996" will be
+     * treated as being equivalent to the 941st day after February 1, 1996.
+     * With strict (non-lenient) interpretation, such dates will cause an exception to be
+     * thrown. The default is lenient.
+     *
+     * @param lenient {@code true} if the lenient mode is to be turned
+     * on; {@code false} if it is to be turned off.
+     * @see #isLenient()
+     * @see java.text.DateFormat#setLenient
+     */
+    public void setLenient(boolean lenient)
+    {
+        this.lenient = lenient;
+    }
+
+    /**
+     * Tells whether date/time interpretation is to be lenient.
+     *
+     * @return {@code true} if the interpretation mode of this calendar is lenient;
+     * {@code false} otherwise.
+     * @see #setLenient(boolean)
+     */
+    public boolean isLenient()
+    {
+        return lenient;
+    }
+
+    /**
+     * Sets what the first day of the week is; e.g., {@code SUNDAY} in the U.S.,
+     * {@code MONDAY} in France.
+     *
+     * @param value the given first day of the week.
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setFirstDayOfWeek(int value)
+    {
+        if (firstDayOfWeek == value) {
+            return;
+        }
+        firstDayOfWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the first day of the week is; e.g., {@code SUNDAY} in the U.S.,
+     * {@code MONDAY} in France.
+     *
+     * @return the first day of the week.
+     * @see #setFirstDayOfWeek(int)
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public int getFirstDayOfWeek()
+    {
+        return firstDayOfWeek;
+    }
+
+    /**
+     * Sets what the minimal days required in the first week of the year are;
+     * For example, if the first week is defined as one that contains the first
+     * day of the first month of a year, call this method with value 1. If it
+     * must be a full week, use value 7.
+     *
+     * @param value the given minimal days required in the first week
+     * of the year.
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setMinimalDaysInFirstWeek(int value)
+    {
+        if (minimalDaysInFirstWeek == value) {
+            return;
+        }
+        minimalDaysInFirstWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the minimal days required in the first week of the year are;
+     * e.g., if the first week is defined as one that contains the first day
+     * of the first month of a year, this method returns 1. If
+     * the minimal days required must be a full week, this method
+     * returns 7.
+     *
+     * @return the minimal days required in the first week of the year.
+     * @see #setMinimalDaysInFirstWeek(int)
+     */
+    public int getMinimalDaysInFirstWeek()
+    {
+        return minimalDaysInFirstWeek;
+    }
+
+    /**
+     * Returns whether this {@code Calendar} supports week dates.
+     *
+     * <p>The default implementation of this method returns {@code false}.
+     *
+     * @return {@code true} if this {@code Calendar} supports week dates;
+     *         {@code false} otherwise.
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    public boolean isWeekDateSupported() {
+        return false;
+    }
+
+    /**
+     * Returns the week year represented by this {@code Calendar}. The
+     * week year is in sync with the week cycle. The {@linkplain
+     * #getFirstDayOfWeek() first day of the first week} is the first
+     * day of the week year.
+     *
+     * <p>The default implementation of this method throws an
+     * {@link UnsupportedOperationException}.
+     *
+     * @return the week year of this {@code Calendar}
+     * @throws    UnsupportedOperationException
+     *            if any week year numbering isn't supported
+     *            in this {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public int getWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Sets the date of this {@code Calendar} with the given date
+     * specifiers - week year, week of year, and day of week.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and {@code time} values are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year range
+     * in {@code weekYear}, the {@code weekYear} and {@code
+     * weekOfYear} values are adjusted in lenient mode, or an {@code
+     * IllegalArgumentException} is thrown in non-lenient mode.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @param weekYear   the week year
+     * @param weekOfYear the week number based on {@code weekYear}
+     * @param dayOfWeek  the day of week value: one of the constants
+     *                   for the {@link #DAY_OF_WEEK} field: {@link
+     *                   #SUNDAY}, ..., {@link #SATURDAY}.
+     * @throws    IllegalArgumentException
+     *            if any of the given date specifiers is invalid
+     *            or any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @throws    UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the number of weeks in the week year represented by this
+     * {@code Calendar}.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return the number of weeks in the week year.
+     * @throws    UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #WEEK_OF_YEAR
+     * @see #isWeekDateSupported()
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    public int getWeeksInWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * {@code Calendar} instance. The minimum value is defined as
+     * the smallest value returned by the {@link #get(int) get} method
+     * for any possible time value.  The minimum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public abstract int getMinimum(int field);
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * {@code Calendar} instance. The maximum value is defined as
+     * the largest value returned by the {@link #get(int) get} method
+     * for any possible time value. The maximum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public abstract int getMaximum(int field);
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this {@code Calendar} instance. The highest minimum
+     * value is defined as the largest value returned by {@link
+     * #getActualMinimum(int)} for any possible time value. The
+     * greatest minimum value depends on calendar system specific
+     * parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public abstract int getGreatestMinimum(int field);
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this {@code Calendar} instance. The lowest maximum
+     * value is defined as the smallest value returned by {@link
+     * #getActualMaximum(int)} for any possible time value. The least
+     * maximum value depends on calendar system specific parameters of
+     * the instance. For example, a {@code Calendar} for the
+     * Gregorian calendar system returns 28 for the
+     * {@code DAY_OF_MONTH} field, because the 28th is the last
+     * day of the shortest month of this calendar, February in a
+     * common year.
+     *
+     * @param field the calendar field.
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public abstract int getLeastMaximum(int field);
+
+    /**
+     * Returns the minimum value that the specified calendar field
+     * could have, given the time value of this {@code Calendar}.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual minimum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation - in many cases, they can
+     * simply return {@code getMinimum()}.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given calendar field for the time
+     * value of this {@code Calendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    public int getActualMinimum(int field) {
+        int fieldValue = getGreatestMinimum(field);
+        int endValue = getMinimum(field);
+
+        // if we know that the minimum value is always the same, just return it
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual minimum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue--;
+            }
+        } while (fieldValue >= endValue);
+
+        return result;
+    }
+
+    /**
+     * Returns the maximum value that the specified calendar field
+     * could have, given the time value of this
+     * {@code Calendar}. For example, the actual maximum value of
+     * the {@code MONTH} field is 12 in some years, and 13 in
+     * other years in the Hebrew calendar system.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual maximum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given calendar field for the time
+     * value of this {@code Calendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    public int getActualMaximum(int field) {
+        int fieldValue = getLeastMaximum(field);
+        int endValue = getMaximum(field);
+
+        // if we know that the maximum value is always the same, just return it.
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values.
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // if we're counting weeks, set the day of the week to Sunday.  We know the
+        // last week of a month or year will contain the first day of the week.
+        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) {
+            work.set(DAY_OF_WEEK, firstDayOfWeek);
+        }
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual maximum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue++;
+            }
+        } while (fieldValue <= endValue);
+
+        return result;
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * @return a copy of this object.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Calendar other = (Calendar) super.clone();
+
+            other.fields = new int[FIELD_COUNT];
+            other.isSet = new boolean[FIELD_COUNT];
+            other.stamp = new int[FIELD_COUNT];
+            for (int i = 0; i < FIELD_COUNT; i++) {
+                other.fields[i] = fields[i];
+                other.stamp[i] = stamp[i];
+                other.isSet[i] = isSet[i];
+            }
+            if (!sharedZone) {
+                other.zone = (TimeZone) zone.clone();
+            }
+            return other;
+        }
+        catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    private static final String[] FIELD_NAME = {
+        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
+        "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
+        "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
+        "DST_OFFSET"
+    };
+
+    /**
+     * Returns the name of the specified calendar field.
+     *
+     * @param field the calendar field
+     * @return the calendar field name
+     * @throws    IndexOutOfBoundsException if {@code field} is negative,
+     * equal to or greater than {@code FIELD_COUNT}.
+     */
+    static String getFieldName(int field) {
+        return FIELD_NAME[field];
+    }
+
+    /**
+     * Return a string representation of this calendar. This method
+     * is intended to be used only for debugging purposes, and the
+     * format of the returned string may vary between implementations.
+     * The returned string may be empty but may not be {@code null}.
+     *
+     * @return  a string representation of this calendar.
+     */
+    @Override
+    public String toString() {
+        // NOTE: BuddhistCalendar.toString() interprets the string
+        // produced by this method so that the Gregorian year number
+        // is substituted by its B.E. year value. It relies on
+        // "...,YEAR=<year>,..." or "...,YEAR=?,...".
+        StringBuilder buffer = new StringBuilder(800);
+        buffer.append(getClass().getName()).append('[');
+        appendValue(buffer, "time", isTimeSet, time);
+        buffer.append(",areFieldsSet=").append(areFieldsSet);
+        buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
+        buffer.append(",lenient=").append(lenient);
+        buffer.append(",zone=").append(zone);
+        appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
+        appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
+        for (int i = 0; i < FIELD_COUNT; ++i) {
+            buffer.append(',');
+            appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    // =======================privates===============================
+
+    private static void appendValue(StringBuilder sb, String item, boolean valid, long value) {
+        sb.append(item).append('=');
+        if (valid) {
+            sb.append(value);
+        } else {
+            sb.append('?');
+        }
+    }
+
+    /**
+     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
+     * They are used to figure out the week count for a specific date for
+     * a given locale. These must be set when a Calendar is constructed.
+     * @param desiredLocale the given locale.
+     */
+    private void setWeekCountData(Locale desiredLocale)
+    {
+        desiredLocale = LocaleData.getCompatibleLocaleForBug159514442(desiredLocale);
+        /* try to get the Locale data from the cache */
+        int[] data = cachedLocaleData.get(desiredLocale);
+        if (data == null) {  /* cache miss */
+            data = new int[2];
+            // BEGIN Android-changed: Use ICU4C to get week data.
+            // data[0] = CalendarDataUtility.retrieveFirstDayOfWeek(desiredLocale);
+            // data[1] = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(desiredLocale);
+            LocaleData localeData = LocaleData.get(desiredLocale);
+            data[0] = localeData.firstDayOfWeek.intValue();
+            data[1] = localeData.minimalDaysInFirstWeek.intValue();
+            // END Android-changed: Use ICU4C to get week data.
+            cachedLocaleData.putIfAbsent(desiredLocale, data);
+        }
+        firstDayOfWeek = data[0];
+        minimalDaysInFirstWeek = data[1];
+    }
+
+    /**
+     * Recomputes the time and updates the status fields isTimeSet
+     * and areFieldsSet.  Callers should check isTimeSet and only
+     * call this method if isTimeSet is false.
+     */
+    private void updateTime() {
+        computeTime();
+        // The areFieldsSet and areAllFieldsSet values are no longer
+        // controlled here (as of 1.5).
+        isTimeSet = true;
+    }
+
+    private int compareTo(long t) {
+        long thisTime = getMillisOf(this);
+        return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
+    }
+
+    private static long getMillisOf(Calendar calendar) {
+        if (calendar.isTimeSet) {
+            return calendar.time;
+        }
+        Calendar cal = (Calendar) calendar.clone();
+        cal.setLenient(true);
+        return cal.getTimeInMillis();
+    }
+
+    /**
+     * Adjusts the stamp[] values before nextStamp overflow. nextStamp
+     * is set to the next stamp value upon the return.
+     */
+    private void adjustStamp() {
+        int max = MINIMUM_USER_STAMP;
+        int newStamp = MINIMUM_USER_STAMP;
+
+        for (;;) {
+            int min = Integer.MAX_VALUE;
+            for (int v : stamp) {
+                if (v >= newStamp && min > v) {
+                    min = v;
+                }
+                if (max < v) {
+                    max = v;
+                }
+            }
+            if (max != min && min == Integer.MAX_VALUE) {
+                break;
+            }
+            for (int i = 0; i < stamp.length; i++) {
+                if (stamp[i] == min) {
+                    stamp[i] = newStamp;
+                }
+            }
+            newStamp++;
+            if (min == max) {
+                break;
+            }
+        }
+        nextStamp = newStamp;
+    }
+
+    /**
+     * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
+     * new parameter value if they have been calculated internally.
+     */
+    private void invalidateWeekFields()
+    {
+        if (stamp[WEEK_OF_MONTH] != COMPUTED &&
+            stamp[WEEK_OF_YEAR] != COMPUTED) {
+            return;
+        }
+
+        // We have to check the new values of these fields after changing
+        // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
+        // have been changed, then set the new values. (4822110)
+        Calendar cal = (Calendar) clone();
+        cal.setLenient(true);
+        cal.clear(WEEK_OF_MONTH);
+        cal.clear(WEEK_OF_YEAR);
+
+        if (stamp[WEEK_OF_MONTH] == COMPUTED) {
+            int weekOfMonth = cal.get(WEEK_OF_MONTH);
+            if (fields[WEEK_OF_MONTH] != weekOfMonth) {
+                fields[WEEK_OF_MONTH] = weekOfMonth;
+            }
+        }
+
+        if (stamp[WEEK_OF_YEAR] == COMPUTED) {
+            int weekOfYear = cal.get(WEEK_OF_YEAR);
+            if (fields[WEEK_OF_YEAR] != weekOfYear) {
+                fields[WEEK_OF_YEAR] = weekOfYear;
+            }
+        }
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * Ideally, {@code Calendar} would only write out its state data and
+     * the current time, and not write any field data out, such as
+     * {@code fields[]}, {@code isTimeSet}, {@code areFieldsSet},
+     * and {@code isSet[]}.  {@code nextStamp} also should not be part
+     * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
+     * shipped. To be compatible with JDK 1.1, we will always have to write out
+     * the field values and state flags.  However, {@code nextStamp} can be
+     * removed from the serialization stream; this will probably happen in the
+     * near future.
+     */
+    @java.io.Serial
+    private synchronized void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Try to compute the time correctly, for the future (stream
+        // version 2) in which we don't write out fields[] or isSet[].
+        if (!isTimeSet) {
+            try {
+                updateTime();
+            }
+            catch (IllegalArgumentException e) {}
+        }
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+        // Write out the 1.1 FCS object.
+        stream.defaultWriteObject();
+    }
+
+    @SuppressWarnings("removal")
+    private static class CalendarAccessControlContext {
+        private static final AccessControlContext INSTANCE;
+        static {
+            RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
+            PermissionCollection perms = perm.newPermissionCollection();
+            perms.add(perm);
+            INSTANCE = new AccessControlContext(new ProtectionDomain[] {
+                                                    new ProtectionDomain(null, perms)
+                                                });
+        }
+        private CalendarAccessControlContext() {
+        }
+    }
+
+    /**
+     * Reconstitutes this object from a stream (i.e., deserialize it).
+     */
+    @SuppressWarnings("removal")
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        final ObjectInputStream input = stream;
+        input.defaultReadObject();
+
+        stamp = new int[FIELD_COUNT];
+
+        // Starting with version 2 (not implemented yet), we expect that
+        // fields[], isSet[], isTimeSet, and areFieldsSet may not be
+        // streamed out anymore.  We expect 'time' to be correct.
+        if (serialVersionOnStream >= 2)
+        {
+            isTimeSet = true;
+            if (fields == null) {
+                fields = new int[FIELD_COUNT];
+            }
+            if (isSet == null) {
+                isSet = new boolean[FIELD_COUNT];
+            }
+        }
+        else if (serialVersionOnStream >= 0)
+        {
+            for (int i=0; i<FIELD_COUNT; ++i) {
+                stamp[i] = isSet[i] ? COMPUTED : UNSET;
+            }
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+        /*
+        // If there's a ZoneInfo object, use it for zone.
+        ZoneInfo zi = null;
+        try {
+            zi = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<>() {
+                        @Override
+                        public ZoneInfo run() throws Exception {
+                            return (ZoneInfo) input.readObject();
+                        }
+                    },
+                    CalendarAccessControlContext.INSTANCE);
+        } catch (PrivilegedActionException pae) {
+            Exception e = pae.getException();
+            if (!(e instanceof OptionalDataException)) {
+                if (e instanceof RuntimeException) {
+                    throw (RuntimeException) e;
+                } else if (e instanceof IOException) {
+                    throw (IOException) e;
+                } else if (e instanceof ClassNotFoundException) {
+                    throw (ClassNotFoundException) e;
+                }
+                throw new RuntimeException(e);
+            }
+        }
+        if (zi != null) {
+            zone = zi;
+        }
+        */
+
+        // If the deserialized object has a SimpleTimeZone, try to
+        // replace it with a ZoneInfo equivalent (as of 1.4) in order
+        // to be compatible with the SimpleTimeZone-based
+        // implementation as much as possible.
+        if (zone instanceof SimpleTimeZone) {
+            String id = zone.getID();
+            TimeZone tz = TimeZone.getTimeZone(id);
+            if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
+                zone = tz;
+            }
+        }
+    }
+
+    /**
+     * Converts this object to an {@link Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the
+     * same point on the time-line as this {@code Calendar}.
+     *
+     * @return the instant representing the same point on the time-line
+     * @since 1.8
+     */
+    public final Instant toInstant() {
+        return Instant.ofEpochMilli(getTimeInMillis());
+    }
+}
diff --git a/android-35/java/util/Collection.java b/android-35/java/util/Collection.java
new file mode 100644
index 0000000..b647526
--- /dev/null
+++ b/android-35/java/util/Collection.java
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * The root interface in the <i>collection hierarchy</i>.  A collection
+ * represents a group of objects, known as its <i>elements</i>.  Some
+ * collections allow duplicate elements and others do not.  Some are ordered
+ * and others unordered.  The JDK does not provide any <i>direct</i>
+ * implementations of this interface: it provides implementations of more
+ * specific subinterfaces like {@code Set} and {@code List}.  This interface
+ * is typically used to pass collections around and manipulate them where
+ * maximum generality is desired.
+ *
+ * <p><i>Bags</i> or <i>multisets</i> (unordered collections that may contain
+ * duplicate elements) should implement this interface directly.
+ *
+ * <p>All general-purpose {@code Collection} implementation classes (which
+ * typically implement {@code Collection} indirectly through one of its
+ * subinterfaces) should provide two "standard" constructors: a void (no
+ * arguments) constructor, which creates an empty collection, and a
+ * constructor with a single argument of type {@code Collection}, which
+ * creates a new collection with the same elements as its argument.  In
+ * effect, the latter constructor allows the user to copy any collection,
+ * producing an equivalent collection of the desired implementation type.
+ * There is no way to enforce this convention (as interfaces cannot contain
+ * constructors) but all of the general-purpose {@code Collection}
+ * implementations in the Java platform libraries comply.
+ *
+ * <p>Certain methods are specified to be
+ * <i>optional</i>. If a collection implementation doesn't implement a
+ * particular operation, it should define the corresponding method to throw
+ * {@code UnsupportedOperationException}. Such methods are marked "optional
+ * operation" in method specifications of the collections interfaces.
+ *
+ * <p><a id="optional-restrictions"></a>Some collection implementations
+ * have restrictions on the elements that they may contain.
+ * For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the collection may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>It is up to each collection to determine its own synchronization
+ * policy.  In the absence of a stronger guarantee by the
+ * implementation, undefined behavior may result from the invocation
+ * of any method on a collection that is being mutated by another
+ * thread; this includes direct invocations, passing the collection to
+ * a method that might perform invocations, and using an existing
+ * iterator to examine the collection.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined in
+ * terms of the {@link Object#equals(Object) equals} method.  For example,
+ * the specification for the {@link #contains(Object) contains(Object o)}
+ * method says: "returns {@code true} if and only if this collection
+ * contains at least one element {@code e} such that
+ * {@code (o==null ? e==null : o.equals(e))}."  This specification should
+ * <i>not</i> be construed to imply that invoking {@code Collection.contains}
+ * with a non-null argument {@code o} will cause {@code o.equals(e)} to be
+ * invoked for any element {@code e}.  Implementations are free to implement
+ * optimizations whereby the {@code equals} invocation is avoided, for
+ * example, by first comparing the hash codes of the two elements.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some collection operations which perform recursive traversal of the
+ * collection may fail with an exception for self-referential instances where
+ * the collection directly or indirectly contains itself. This includes the
+ * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()}
+ * methods. Implementations may optionally handle the self-referential scenario,
+ * however most current implementations do not do so.
+ *
+ * <h2><a id="view">View Collections</a></h2>
+ *
+ * <p>Most collections manage storage for elements they contain. By contrast, <i>view
+ * collections</i> themselves do not store elements, but instead they rely on a
+ * backing collection to store the actual elements. Operations that are not handled
+ * by the view collection itself are delegated to the backing collection. Examples of
+ * view collections include the wrapper collections returned by methods such as
+ * {@link Collections#checkedCollection Collections.checkedCollection},
+ * {@link Collections#synchronizedCollection Collections.synchronizedCollection}, and
+ * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection}.
+ * Other examples of view collections include collections that provide a
+ * different representation of the same elements, for example, as
+ * provided by {@link List#subList List.subList},
+ * {@link NavigableSet#subSet NavigableSet.subSet}, or
+ * {@link Map#entrySet Map.entrySet}.
+ * Any changes made to the backing collection are visible in the view collection.
+ * Correspondingly, any changes made to the view collection &mdash; if changes
+ * are permitted &mdash; are written through to the backing collection.
+ * Although they technically aren't collections, instances of
+ * {@link Iterator} and {@link ListIterator} can also allow modifications
+ * to be written through to the backing collection, and in some cases,
+ * modifications to the backing collection will be visible to the Iterator
+ * during iteration.
+ *
+ * <h2><a id="unmodifiable">Unmodifiable Collections</a></h2>
+ *
+ * <p>Certain methods of this interface are considered "destructive" and are called
+ * "mutator" methods in that they modify the group of objects contained within
+ * the collection on which they operate. They can be specified to throw
+ * {@code UnsupportedOperationException} if this collection implementation
+ * does not support the operation. Such methods should (but are not required
+ * to) throw an {@code UnsupportedOperationException} if the invocation would
+ * have no effect on the collection. For example, consider a collection that
+ * does not support the {@link #add add} operation. What will happen if the
+ * {@link #addAll addAll} method is invoked on this collection, with an empty
+ * collection as the argument? The addition of zero elements has no effect,
+ * so it is permissible for this collection simply to do nothing and not to throw
+ * an exception. However, it is recommended that such cases throw an exception
+ * unconditionally, as throwing only in certain cases can lead to
+ * programming errors.
+ *
+ * <p>An <i>unmodifiable collection</i> is a collection, all of whose
+ * mutator methods (as defined above) are specified to throw
+ * {@code UnsupportedOperationException}. Such a collection thus cannot be
+ * modified by calling any methods on it. For a collection to be properly
+ * unmodifiable, any view collections derived from it must also be unmodifiable.
+ * For example, if a List is unmodifiable, the List returned by
+ * {@link List#subList List.subList} is also unmodifiable.
+ *
+ * <p>An unmodifiable collection is not necessarily immutable. If the
+ * contained elements are mutable, the entire collection is clearly
+ * mutable, even though it might be unmodifiable. For example, consider
+ * two unmodifiable lists containing mutable elements. The result of calling
+ * {@code list1.equals(list2)} might differ from one call to the next if
+ * the elements had been mutated, even though both lists are unmodifiable.
+ * However, if an unmodifiable collection contains all immutable elements,
+ * it can be considered effectively immutable.
+ *
+ * <h2><a id="unmodview">Unmodifiable View Collections</a></h2>
+ *
+ * <p>An <i>unmodifiable view collection</i> is a collection that is unmodifiable
+ * and that is also a view onto a backing collection. Its mutator methods throw
+ * {@code UnsupportedOperationException}, as described above, while
+ * reading and querying methods are delegated to the backing collection.
+ * The effect is to provide read-only access to the backing collection.
+ * This is useful for a component to provide users with read access to
+ * an internal collection, while preventing them from modifying such
+ * collections unexpectedly. Examples of unmodifiable view collections
+ * are those returned by the
+ * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection},
+ * {@link Collections#unmodifiableList Collections.unmodifiableList}, and
+ * related methods.
+ *
+ * <p>Note that changes to the backing collection might still be possible,
+ * and if they occur, they are visible through the unmodifiable view. Thus,
+ * an unmodifiable view collection is not necessarily immutable. However,
+ * if the backing collection of an unmodifiable view is effectively immutable,
+ * or if the only reference to the backing collection is through an
+ * unmodifiable view, the view can be considered effectively immutable.
+ *
+ * <h2><a id="serializable">Serializability of Collections</a></h2>
+ *
+ * <p>Serializability of collections is optional. As such, none of the collections
+ * interfaces are declared to implement the {@link java.io.Serializable} interface.
+ * However, serializability is regarded as being generally useful, so most collection
+ * implementations are serializable.
+ *
+ * <p>The collection implementations that are public classes (such as {@code ArrayList}
+ * or {@code HashMap}) are declared to implement the {@code Serializable} interface if they
+ * are in fact serializable. Some collections implementations are not public classes,
+ * such as the <a href="#unmodifiable">unmodifiable collections.</a> In such cases, the
+ * serializability of such collections is described in the specification of the method
+ * that creates them, or in some other suitable place. In cases where the serializability
+ * of a collection is not specified, there is no guarantee about the serializability of such
+ * collections. In particular, many <a href="#view">view collections</a> are not serializable.
+ *
+ * <p>A collection implementation that implements the {@code Serializable} interface cannot
+ * be guaranteed to be serializable. The reason is that in general, collections
+ * contain elements of other types, and it is not possible to determine statically
+ * whether instances of some element type are actually serializable. For example, consider
+ * a serializable {@code Collection<E>}, where {@code E} does not implement the
+ * {@code Serializable} interface. The collection may be serializable, if it contains only
+ * elements of some serializable subtype of {@code E}, or if it is empty. Collections are
+ * thus said to be <i>conditionally serializable,</i> as the serializability of the collection
+ * as a whole depends on whether the collection itself is serializable and on whether all
+ * contained elements are also serializable.
+ *
+ * <p>An additional case occurs with instances of {@link SortedSet} and {@link SortedMap}.
+ * These collections can be created with a {@link Comparator} that imposes an ordering on
+ * the set elements or map keys. Such a collection is serializable only if the provided
+ * {@code Comparator} is also serializable.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @implSpec
+ * The default method implementations (inherited or otherwise) do not apply any
+ * synchronization protocol.  If a {@code Collection} implementation has a
+ * specific synchronization protocol, then it must override default
+ * implementations to apply that protocol.
+ *
+ * @param <E> the type of elements in this collection
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @see     SortedSet
+ * @see     SortedMap
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     ArrayList
+ * @see     LinkedList
+ * @see     Vector
+ * @see     Collections
+ * @see     Arrays
+ * @see     AbstractCollection
+ * @since 1.2
+ */
+
+public interface Collection<E> extends Iterable<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this collection.  If this collection
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this collection
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this collection contains no elements.
+     *
+     * @return {@code true} if this collection contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this collection contains the specified element.
+     * More formally, returns {@code true} if and only if this collection
+     * contains at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this collection is to be tested
+     * @return {@code true} if this collection contains the specified
+     *         element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this collection.  There are no
+     * guarantees concerning the order in which the elements are returned
+     * (unless this collection is an instance of some class that provides a
+     * guarantee).
+     *
+     * @return an {@code Iterator} over the elements in this collection
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this collection.
+     * If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order. The returned array's {@linkplain Class#getComponentType
+     * runtime component type} is {@code Object}.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this collection.  (In other words, this method must
+     * allocate a new array even if this collection is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * @apiNote
+     * This method acts as a bridge between array-based and collection-based APIs.
+     * It returns an array whose runtime type is {@code Object[]}.
+     * Use {@link #toArray(Object[]) toArray(T[])} to reuse an existing
+     * array, or use {@link #toArray(IntFunction)} to control the runtime type
+     * of the array.
+     *
+     * @return an array, whose {@linkplain Class#getComponentType runtime component
+     * type} is {@code Object}, containing all of the elements in this collection
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this collection;
+     * the runtime type of the returned array is that of the specified array.
+     * If the collection fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this collection.
+     *
+     * <p>If this collection fits in the specified array with room to spare
+     * (i.e., the array has more elements than this collection), the element
+     * in the array immediately following the end of the collection is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * collection <i>only</i> if the caller knows that this collection does
+     * not contain any {@code null} elements.)
+     *
+     * <p>If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * @apiNote
+     * This method acts as a bridge between array-based and collection-based APIs.
+     * It allows an existing array to be reused under certain circumstances.
+     * Use {@link #toArray()} to create an array whose runtime type is {@code Object[]},
+     * or use {@link #toArray(IntFunction)} to control the runtime type of
+     * the array.
+     *
+     * <p>Suppose {@code x} is a collection known to contain only strings.
+     * The following code can be used to dump the collection into a previously
+     * allocated {@code String} array:
+     *
+     * <pre>
+     *     String[] y = new String[SIZE];
+     *     ...
+     *     y = x.toArray(y);</pre>
+     *
+     * <p>The return value is reassigned to the variable {@code y}, because a
+     * new array will be allocated and returned if the collection {@code x} has
+     * too many elements to fit into the existing array {@code y}.
+     *
+     * <p>Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param <T> the component type of the array to contain the collection
+     * @param a the array into which the elements of this collection are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this collection
+     * @throws ArrayStoreException if the runtime type of any element in this
+     *         collection is not assignable to the {@linkplain Class#getComponentType
+     *         runtime component type} of the specified array
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+    /**
+     * Returns an array containing all of the elements in this collection,
+     * using the provided {@code generator} function to allocate the returned array.
+     *
+     * <p>If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * @apiNote
+     * This method acts as a bridge between array-based and collection-based APIs.
+     * It allows creation of an array of a particular runtime type. Use
+     * {@link #toArray()} to create an array whose runtime type is {@code Object[]},
+     * or use {@link #toArray(Object[]) toArray(T[])} to reuse an existing array.
+     *
+     * <p>Suppose {@code x} is a collection known to contain only strings.
+     * The following code can be used to dump the collection into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(String[]::new);</pre>
+     *
+     * @implSpec
+     * The default implementation calls the generator function with zero
+     * and then passes the resulting array to {@link #toArray(Object[]) toArray(T[])}.
+     *
+     * @param <T> the component type of the array to contain the collection
+     * @param generator a function which produces a new array of the desired
+     *                  type and the provided length
+     * @return an array containing all of the elements in this collection
+     * @throws ArrayStoreException if the runtime type of any element in this
+     *         collection is not assignable to the {@linkplain Class#getComponentType
+     *         runtime component type} of the generated array
+     * @throws NullPointerException if the generator function is null
+     * @since 11
+     */
+    default <T> T[] toArray(IntFunction<T[]> generator) {
+        return toArray(generator.apply(0));
+    }
+
+    // Modification Operations
+
+    /**
+     * Ensures that this collection contains the specified element (optional
+     * operation).  Returns {@code true} if this collection changed as a
+     * result of the call.  (Returns {@code false} if this collection does
+     * not permit duplicates and already contains the specified element.)<p>
+     *
+     * Collections that support this operation may place limitations on what
+     * elements may be added to this collection.  In particular, some
+     * collections will refuse to add {@code null} elements, and others will
+     * impose restrictions on the type of elements that may be added.
+     * Collection classes should clearly specify in their documentation any
+     * restrictions on what elements may be added.<p>
+     *
+     * If a collection refuses to add a particular element for any reason
+     * other than that it already contains the element, it <i>must</i> throw
+     * an exception (rather than returning {@code false}).  This preserves
+     * the invariant that a collection always contains the specified element
+     * after this call returns.
+     *
+     * @param e element whose presence in this collection is to be ensured
+     * @return {@code true} if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this collection
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     * @throws IllegalArgumentException if some property of the element
+     *         prevents it from being added to this collection
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to insertion restrictions
+     */
+    boolean add(E e);
+
+    /**
+     * Removes a single instance of the specified element from this
+     * collection, if it is present (optional operation).  More formally,
+     * removes an element {@code e} such that
+     * {@code Objects.equals(o, e)}, if
+     * this collection contains one or more such elements.  Returns
+     * {@code true} if this collection contained the specified element (or
+     * equivalently, if this collection changed as a result of the call).
+     *
+     * @param o element to be removed from this collection, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     *         is not supported by this collection
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this collection contains all of the elements
+     * in the specified collection.
+     *
+     * @param  c collection to be checked for containment in this collection
+     * @return {@code true} if this collection contains all of the elements
+     *         in the specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null.
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this collection
+     * (optional operation).  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified collection is this collection, and this collection is
+     * nonempty.)
+     *
+     * @param c collection containing elements to be added to this collection
+     * @return {@code true} if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this collection
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this collection does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         collection
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Removes all of this collection's elements that are also contained in the
+     * specified collection (optional operation).  After this call returns,
+     * this collection will contain no elements in common with the specified
+     * collection.
+     *
+     * @param c collection containing elements to be removed from this collection
+     * @return {@code true} if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the {@code removeAll} method
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not support
+     *         null elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements of this collection that satisfy the given
+     * predicate.  Errors or runtime exceptions thrown during iteration or by
+     * the predicate are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation traverses all elements of the collection using
+     * its {@link #iterator}.  Each matching element is removed using
+     * {@link Iterator#remove()}.  If the collection's iterator does not
+     * support removal then an {@code UnsupportedOperationException} will be
+     * thrown on the first matching element.
+     *
+     * @param filter a predicate which returns {@code true} for elements to be
+     *        removed
+     * @return {@code true} if any elements were removed
+     * @throws NullPointerException if the specified filter is null
+     * @throws UnsupportedOperationException if elements cannot be removed
+     *         from this collection.  Implementations may throw this exception if a
+     *         matching element cannot be removed or if, in general, removal is not
+     *         supported.
+     * @since 1.8
+     */
+    default boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        boolean removed = false;
+        final Iterator<E> each = iterator();
+        while (each.hasNext()) {
+            if (filter.test(each.next())) {
+                each.remove();
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Retains only the elements in this collection that are contained in the
+     * specified collection (optional operation).  In other words, removes from
+     * this collection all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this collection
+     * @return {@code true} if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this collection (optional operation).
+     * The collection will be empty after this method returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this collection
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this collection for equality. <p>
+     *
+     * While the {@code Collection} interface adds no stipulations to the
+     * general contract for the {@code Object.equals}, programmers who
+     * implement the {@code Collection} interface "directly" (in other words,
+     * create a class that is a {@code Collection} but is not a {@code Set}
+     * or a {@code List}) must exercise care if they choose to override the
+     * {@code Object.equals}.  It is not necessary to do so, and the simplest
+     * course of action is to rely on {@code Object}'s implementation, but
+     * the implementor may wish to implement a "value comparison" in place of
+     * the default "reference comparison."  (The {@code List} and
+     * {@code Set} interfaces mandate such value comparisons.)<p>
+     *
+     * The general contract for the {@code Object.equals} method states that
+     * equals must be symmetric (in other words, {@code a.equals(b)} if and
+     * only if {@code b.equals(a)}).  The contracts for {@code List.equals}
+     * and {@code Set.equals} state that lists are only equal to other lists,
+     * and sets to other sets.  Thus, a custom {@code equals} method for a
+     * collection class that implements neither the {@code List} nor
+     * {@code Set} interface must return {@code false} when this collection
+     * is compared to any list or set.  (By the same logic, it is not possible
+     * to write a class that correctly implements both the {@code Set} and
+     * {@code List} interfaces.)
+     *
+     * @param o object to be compared for equality with this collection
+     * @return {@code true} if the specified object is equal to this
+     * collection
+     *
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     * @see List#equals(Object)
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this collection.  While the
+     * {@code Collection} interface adds no stipulations to the general
+     * contract for the {@code Object.hashCode} method, programmers should
+     * take note that any class that overrides the {@code Object.equals}
+     * method must also override the {@code Object.hashCode} method in order
+     * to satisfy the general contract for the {@code Object.hashCode} method.
+     * In particular, {@code c1.equals(c2)} implies that
+     * {@code c1.hashCode()==c2.hashCode()}.
+     *
+     * @return the hash code value for this collection
+     *
+     * @see Object#hashCode()
+     * @see Object#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this collection.
+     *
+     * Implementations should document characteristic values reported by the
+     * spliterator.  Such characteristic values are not required to be reported
+     * if the spliterator reports {@link Spliterator#SIZED} and this collection
+     * contains no elements.
+     *
+     * <p>The default implementation should be overridden by subclasses that
+     * can return a more efficient spliterator.  In order to
+     * preserve expected laziness behavior for the {@link #stream()} and
+     * {@link #parallelStream()} methods, spliterators should either have the
+     * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>.
+     * If none of these is practical, the overriding class should describe the
+     * spliterator's documented policy of binding and structural interference,
+     * and should override the {@link #stream()} and {@link #parallelStream()}
+     * methods to create streams using a {@code Supplier} of the spliterator,
+     * as in:
+     * <pre>{@code
+     *     Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
+     * }</pre>
+     * <p>These requirements ensure that streams produced by the
+     * {@link #stream()} and {@link #parallelStream()} methods will reflect the
+     * contents of the collection as of initiation of the terminal stream
+     * operation.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the collection's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the collection's iterator.
+     * <p>
+     * The created {@code Spliterator} reports {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>If a spliterator covers no elements then the reporting of additional
+     * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
+     * does not aid clients to control, specialize or simplify computation.
+     * However, this does enable shared use of an immutable and empty
+     * spliterator instance (see {@link Spliterators#emptySpliterator()}) for
+     * empty collections, and enables clients to determine if such a spliterator
+     * covers no elements.
+     *
+     * @return a {@code Spliterator} over the elements in this collection
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, 0);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} with this collection as its source.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a sequential {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a sequential {@code Stream} over the elements in this collection
+     * @since 1.8
+     */
+    default Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    /**
+     * Returns a possibly parallel {@code Stream} with this collection as its
+     * source.  It is allowable for this method to return a sequential stream.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a parallel {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a possibly parallel {@code Stream} over the elements in this
+     * collection
+     * @since 1.8
+     */
+    default Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+}
diff --git a/android-35/java/util/Collections.java b/android-35/java/util/Collections.java
new file mode 100644
index 0000000..03b0d22
--- /dev/null
+++ b/android-35/java/util/Collections.java
@@ -0,0 +1,6211 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.random.RandomGenerator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.access.SharedSecrets;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * collections.  It contains polymorphic algorithms that operate on
+ * collections, "wrappers", which return a new collection backed by a
+ * specified collection, and a few other odds and ends.
+ *
+ * <p>The methods of this class all throw a {@code NullPointerException}
+ * if the collections or class objects provided to them are null.
+ *
+ * <p>The documentation for the polymorphic algorithms contained in this class
+ * generally includes a brief description of the <i>implementation</i>.  Such
+ * descriptions should be regarded as <i>implementation notes</i>, rather than
+ * parts of the <i>specification</i>.  Implementors should feel free to
+ * substitute other algorithms, so long as the specification itself is adhered
+ * to.  (For example, the algorithm used by {@code sort} does not have to be
+ * a mergesort, but it does have to be <i>stable</i>.)
+ *
+ * <p>The "destructive" algorithms contained in this class, that is, the
+ * algorithms that modify the collection on which they operate, are specified
+ * to throw {@code UnsupportedOperationException} if the collection does not
+ * support the appropriate mutation primitive(s), such as the {@code set}
+ * method.  These algorithms may, but are not required to, throw this
+ * exception if an invocation would have no effect on the collection.  For
+ * example, invoking the {@code sort} method on an unmodifiable list that is
+ * already sorted may or may not throw {@code UnsupportedOperationException}.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @since   1.2
+ */
+
+public class Collections {
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Collections() {
+    }
+
+    // Algorithms
+
+    /*
+     * Tuning parameters for algorithms - Many of the List algorithms have
+     * two implementations, one of which is appropriate for RandomAccess
+     * lists, the other for "sequential."  Often, the random access variant
+     * yields better performance on small sequential access lists.  The
+     * tuning parameters below determine the cutoff point for what constitutes
+     * a "small" sequential access list for each algorithm.  The values below
+     * were empirically determined to work well for LinkedList. Hopefully
+     * they should be reasonable for other sequential access List
+     * implementations.  Those doing performance work on this code would
+     * do well to validate the values of these parameters from time to time.
+     * (The first word of each tuning parameter name is the algorithm to which
+     * it applies.)
+     */
+    private static final int BINARYSEARCH_THRESHOLD   = 5000;
+    private static final int REVERSE_THRESHOLD        =   18;
+    private static final int SHUFFLE_THRESHOLD        =    5;
+    private static final int FILL_THRESHOLD           =   25;
+    private static final int ROTATE_THRESHOLD         =  100;
+    private static final int COPY_THRESHOLD           =   10;
+    private static final int REPLACEALL_THRESHOLD     =   11;
+    private static final int INDEXOFSUBLIST_THRESHOLD =   35;
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list into ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the list must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the list must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
+     * must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and a {@code null} comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers).
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the implementation
+     *         detects that the natural ordering of the list elements is
+     *         found to violate the {@link Comparable} contract
+     * @see List#sort(Comparator)
+     */
+    public static <T extends Comparable<? super T>> void sort(List<T> list) {
+        // Android-changed: List.sort() vs. Collections.sort() app compat.
+        // Call sort(list, null) here to be consistent with that method's
+        // (changed on Android) behavior.
+        // list.sort(null);
+        sort(list, null);
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list according to the order induced by the
+     * specified comparator.  All elements in the list must be <i>mutually
+     * comparable</i> using the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @param  c the comparator to determine the order of the list.  A
+     *        {@code null} value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     * @see List#sort(Comparator)
+     */
+    public static <T> void sort(List<T> list, Comparator<? super T> c) {
+        // BEGIN Android-changed: List.sort() vs. Collections.sort() app compat.
+        // list.sort(c);
+        int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 25) {
+            list.sort(c);
+        } else {
+            // Compatibility behavior for API <= 25. http://b/33482884
+            if (list.getClass() == ArrayList.class) {
+                Arrays.sort((T[]) ((ArrayList) list).elementData, 0, list.size(), c);
+                return;
+            }
+
+            Object[] a = list.toArray();
+            Arrays.sort(a, (Comparator) c);
+            ListIterator<T> i = list.listIterator();
+            for (int j = 0; j < a.length; j++) {
+                i.next();
+                i.set((T) a[j]);
+            }
+        }
+        // END Android-changed: List.sort() vs. Collections.sort() app compat.
+    }
+
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the {@linkplain Comparable natural ordering} of its
+     * elements (as by the {@link #sort(List)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.  If the list
+     * contains multiple elements equal to the specified object, there is no
+     * guarantee which one will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or {@code list.size()} if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and
+     *         integers), or the search key is not mutually comparable
+     *         with the elements of the list.
+     */
+    public static <T>
+    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key);
+        else
+            return Collections.iteratorBinarySearch(list, key);
+    }
+
+    private static <T>
+    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
+        int low = 0;
+        int high = list.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = list.get(mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T>
+    int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
+    {
+        int low = 0;
+        int high = list.size()-1;
+        ListIterator<? extends Comparable<? super T>> i = list.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = get(i, mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Gets the ith element from the given list by repositioning the specified
+     * list listIterator.
+     */
+    private static <T> T get(ListIterator<? extends T> i, int index) {
+        T obj;
+        int pos = i.nextIndex();
+        if (pos <= index) {
+            do {
+                obj = i.next();
+            } while (pos++ < index);
+        } else {
+            do {
+                obj = i.previous();
+            } while (--pos > index);
+        }
+        return obj;
+    }
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(List, Comparator) sort(List, Comparator)}
+     * method), prior to making this call.  If it is
+     * not sorted, the results are undefined.  If the list contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @param  c the comparator by which the list is ordered.
+     *         A {@code null} value indicates that the elements'
+     *         {@linkplain Comparable natural ordering} should be used.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or {@code list.size()} if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not mutually comparable with the
+     *         elements of the list using this comparator.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
+        if (c==null)
+            return binarySearch((List<? extends Comparable<? super T>>) list, key);
+
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key, c);
+        else
+            return Collections.iteratorBinarySearch(list, key, c);
+    }
+
+    private static <T> int indexedBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = l.get(mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+        ListIterator<? extends T> i = l.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = get(i, mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Reverses the order of the elements in the specified list.<p>
+     *
+     * This method runs in linear time.
+     *
+     * @apiNote
+     * This method mutates the specified list in-place. To obtain a
+     * reverse-ordered view of a list without mutating it, use the
+     * {@link List#reversed List.reversed} method.
+     *
+     * @param  list the list whose elements are to be reversed.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the {@code set} operation.
+     * @see    List#reversed List.reversed
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void reverse(List<?> list) {
+        int size = list.size();
+        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
+                swap(list, i, j);
+        } else {
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator fwd = list.listIterator();
+            ListIterator rev = list.listIterator(size);
+            for (int i=0, mid=list.size()>>1; i<mid; i++) {
+                Object tmp = fwd.next();
+                fwd.set(rev.previous());
+                rev.set(tmp);
+            }
+        }
+    }
+
+    /**
+     * Randomly permutes the specified list using a default source of
+     * randomness.  All permutations occur with approximately equal
+     * likelihood.
+     *
+     * <p>The hedge "approximately" is used in the foregoing description because
+     * default source of randomness is only approximately an unbiased source
+     * of independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm would choose permutations with perfect
+     * uniformity.
+     *
+     * <p>This implementation traverses the list backwards, from the last
+     * element up to the second, repeatedly swapping a randomly selected element
+     * into the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.
+     *
+     * @implSpec This method runs in linear time.  If the specified list does
+     * not implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the {@code set} operation.
+     */
+    public static void shuffle(List<?> list) {
+        Random rnd = r;
+        if (rnd == null)
+            r = rnd = new Random(); // harmless race.
+        shuffle(list, rnd);
+    }
+
+    private static Random r;
+
+    /**
+     * Randomly permute the specified list using the specified source of
+     * randomness.<p>
+     *
+     * This method is equivalent to {@link #shuffle(List, RandomGenerator)}
+     * and exists for backward compatibility. The {@link #shuffle(List, RandomGenerator)}
+     * method is preferred, as it is not limited to random generators
+     * that extend the {@link Random} class.
+     *
+     * @param  list the list to be shuffled.
+     * @param  rnd the source of randomness to use to shuffle the list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the {@code set} operation.
+     */
+    public static void shuffle(List<?> list, Random rnd) {
+        shuffle(list, (RandomGenerator) rnd);
+    }
+
+    /**
+     * Randomly permute the specified list using the specified source of
+     * randomness.  All permutations occur with equal likelihood
+     * assuming that the source of randomness is fair.<p>
+     *
+     * This implementation traverses the list backwards, from the last element
+     * up to the second, repeatedly swapping a randomly selected element into
+     * the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.
+     *
+     * @implSpec This method runs in linear time.  If the specified list does
+     * not implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @param  rnd the source of randomness to use to shuffle the list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the {@code set} operation.
+     * @since 21
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void shuffle(List<?> list, RandomGenerator rnd) {
+        int size = list.size();
+        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=size; i>1; i--)
+                swap(list, i-1, rnd.nextInt(i));
+        } else {
+            Object[] arr = list.toArray();
+
+            // Shuffle array
+            for (int i=size; i>1; i--)
+                swap(arr, i-1, rnd.nextInt(i));
+
+            // Dump array back into list
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator it = list.listIterator();
+            for (Object e : arr) {
+                it.next();
+                it.set(e);
+            }
+        }
+    }
+
+    /**
+     * Swaps the elements at the specified positions in the specified list.
+     * (If the specified positions are equal, invoking this method leaves
+     * the list unchanged.)
+     *
+     * @param list The list in which to swap elements.
+     * @param i the index of one element to be swapped.
+     * @param j the index of the other element to be swapped.
+     * @throws IndexOutOfBoundsException if either {@code i} or {@code j}
+     *         is out of range (i &lt; 0 || i &gt;= list.size()
+     *         || j &lt; 0 || j &gt;= list.size()).
+     * @since 1.4
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void swap(List<?> list, int i, int j) {
+        // instead of using a raw type here, it's possible to capture
+        // the wildcard but it will require a call to a supplementary
+        // private method
+        final List l = list;
+        l.set(i, l.set(j, l.get(i)));
+    }
+
+    /**
+     * Swaps the two specified elements in the specified array.
+     */
+    private static void swap(Object[] arr, int i, int j) {
+        Object tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
+
+    /**
+     * Replaces all of the elements of the specified list with the specified
+     * element. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be filled with the specified element.
+     * @param  obj The element with which to fill the specified list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the {@code set} operation.
+     */
+    public static <T> void fill(List<? super T> list, T obj) {
+        int size = list.size();
+
+        if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0; i<size; i++)
+                list.set(i, obj);
+        } else {
+            ListIterator<? super T> itr = list.listIterator();
+            for (int i=0; i<size; i++) {
+                itr.next();
+                itr.set(obj);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the elements from one list into another.  After the
+     * operation, the index of each copied element in the destination list
+     * will be identical to its index in the source list.  The destination
+     * list's size must be greater than or equal to the source list's size.
+     * If it is greater, the remaining elements in the destination list are
+     * unaffected. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the lists
+     * @param  dest The destination list.
+     * @param  src The source list.
+     * @throws IndexOutOfBoundsException if the destination list is too small
+     *         to contain the entire source List.
+     * @throws UnsupportedOperationException if the destination list's
+     *         list-iterator does not support the {@code set} operation.
+     */
+    public static <T> void copy(List<? super T> dest, List<? extends T> src) {
+        int srcSize = src.size();
+        if (srcSize > dest.size())
+            throw new IndexOutOfBoundsException("Source does not fit in dest");
+
+        if (srcSize < COPY_THRESHOLD ||
+            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
+            for (int i=0; i<srcSize; i++)
+                dest.set(i, src.get(i));
+        } else {
+            ListIterator<? super T> di=dest.listIterator();
+            ListIterator<? extends T> si=src.listIterator();
+            for (int i=0; i<srcSize; i++) {
+                di.next();
+                di.set(si.next());
+            }
+        }
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the {@code Comparable} interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @return the minimum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, {@code comp.compare(e1, e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @param  comp the comparator with which to determine the minimum element.
+     *         A {@code null} value indicates that the elements' <i>natural
+     *         ordering</i> should be used.
+     * @return the minimum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked"})
+    public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)min((Collection<Comparable<Object>>) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the {@code Comparable} interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @return the maximum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, {@code comp.compare(e1, e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @param  comp the comparator with which to determine the maximum element.
+     *         A {@code null} value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @return the maximum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked"})
+    public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)max((Collection<Comparable<Object>>) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Rotates the elements in the specified list by the specified distance.
+     * After calling this method, the element at index {@code i} will be
+     * the element previously at index {@code (i - distance)} mod
+     * {@code list.size()}, for all values of {@code i} between {@code 0}
+     * and {@code list.size()-1}, inclusive.  (This method has no effect on
+     * the size of the list.)
+     *
+     * <p>For example, suppose {@code list} comprises{@code  [t, a, n, k, s]}.
+     * After invoking {@code Collections.rotate(list, 1)} (or
+     * {@code Collections.rotate(list, -4)}), {@code list} will comprise
+     * {@code [s, t, a, n, k]}.
+     *
+     * <p>Note that this method can usefully be applied to sublists to
+     * move one or more elements within a list while preserving the
+     * order of the remaining elements.  For example, the following idiom
+     * moves the element at index {@code j} forward to position
+     * {@code k} (which must be greater than or equal to {@code j}):
+     * <pre>
+     *     Collections.rotate(list.subList(j, k+1), -1);
+     * </pre>
+     * To make this concrete, suppose {@code list} comprises
+     * {@code [a, b, c, d, e]}.  To move the element at index {@code 1}
+     * ({@code b}) forward two positions, perform the following invocation:
+     * <pre>
+     *     Collections.rotate(l.subList(1, 4), -1);
+     * </pre>
+     * The resulting list is {@code [a, c, d, b, e]}.
+     *
+     * <p>To move more than one element forward, increase the absolute value
+     * of the rotation distance.  To move elements backward, use a positive
+     * shift distance.
+     *
+     * <p>If the specified list is small or implements the {@link
+     * RandomAccess} interface, this implementation exchanges the first
+     * element into the location it should go, and then repeatedly exchanges
+     * the displaced element into the location it should go until a displaced
+     * element is swapped into the first element.  If necessary, the process
+     * is repeated on the second and successive elements, until the rotation
+     * is complete.  If the specified list is large and doesn't implement the
+     * {@code RandomAccess} interface, this implementation breaks the
+     * list into two sublist views around index {@code -distance mod size}.
+     * Then the {@link #reverse(List)} method is invoked on each sublist view,
+     * and finally it is invoked on the entire list.  For a more complete
+     * description of both algorithms, see Section 2.3 of Jon Bentley's
+     * <i>Programming Pearls</i> (Addison-Wesley, 1986).
+     *
+     * @param list the list to be rotated.
+     * @param distance the distance to rotate the list.  There are no
+     *        constraints on this value; it may be zero, negative, or
+     *        greater than {@code list.size()}.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the {@code set} operation.
+     * @since 1.4
+     */
+    public static void rotate(List<?> list, int distance) {
+        if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
+            rotate1(list, distance);
+        else
+            rotate2(list, distance);
+    }
+
+    private static <T> void rotate1(List<T> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        distance = distance % size;
+        if (distance < 0)
+            distance += size;
+        if (distance == 0)
+            return;
+
+        for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
+            T displaced = list.get(cycleStart);
+            int i = cycleStart;
+            do {
+                i += distance;
+                if (i >= size)
+                    i -= size;
+                displaced = list.set(i, displaced);
+                nMoved ++;
+            } while (i != cycleStart);
+        }
+    }
+
+    private static void rotate2(List<?> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        int mid =  -distance % size;
+        if (mid < 0)
+            mid += size;
+        if (mid == 0)
+            return;
+
+        reverse(list.subList(0, mid));
+        reverse(list.subList(mid, size));
+        reverse(list);
+    }
+
+    /**
+     * Replaces all occurrences of one specified value in a list with another.
+     * More formally, replaces with {@code newVal} each element {@code e}
+     * in {@code list} such that
+     * {@code (oldVal==null ? e==null : oldVal.equals(e))}.
+     * (This method has no effect on the size of the list.)
+     *
+     * @param  <T> the class of the objects in the list
+     * @param list the list in which replacement is to occur.
+     * @param oldVal the old value to be replaced.
+     * @param newVal the new value with which {@code oldVal} is to be
+     *        replaced.
+     * @return {@code true} if {@code list} contained one or more elements
+     *         {@code e} such that
+     *         {@code (oldVal==null ?  e==null : oldVal.equals(e))}.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the {@code set} operation.
+     * @since  1.4
+     */
+    public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
+        boolean result = false;
+        int size = list.size();
+        if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (list.get(i)==null) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(list.get(i))) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            }
+        } else {
+            ListIterator<T> itr=list.listIterator();
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (itr.next()==null) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(itr.next())) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the starting position of the first occurrence of the specified
+     * target list within the specified source list, or -1 if there is no
+     * such occurrence.  More formally, returns the lowest index {@code i}
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of scanning
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the first occurrence
+     *        of {@code target}.
+     * @param target the list to search for as a subList of {@code source}.
+     * @return the starting position of the first occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int indexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            (source instanceof RandomAccess&&target instanceof RandomAccess)) {
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            ListIterator<?> si = source.listIterator();
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        // Back up source iterator to next candidate
+                        for (int j=0; j<i; j++)
+                            si.previous();
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+    /**
+     * Returns the starting position of the last occurrence of the specified
+     * target list within the specified source list, or -1 if there is no such
+     * occurrence.  More formally, returns the highest index {@code i}
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of iterating
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the last occurrence
+     *        of {@code target}.
+     * @param target the list to search for as a subList of {@code source}.
+     * @return the starting position of the last occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int lastIndexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            source instanceof RandomAccess) {   // Index access version
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            if (maxCandidate < 0)
+                return -1;
+            ListIterator<?> si = source.listIterator(maxCandidate);
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        if (candidate != 0) {
+                            // Back up source iterator to next candidate
+                            for (int j=0; j<=i+1; j++)
+                                si.previous();
+                        }
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+
+    // Unmodifiable Wrappers
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified collection. Query operations on the returned collection "read through"
+     * to the specified collection, and attempts to modify the returned
+     * collection, whether direct or via its iterator, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * {@code Object}'s {@code equals} and {@code hashCode} methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection for which an unmodifiable view is to be
+     *         returned.
+     * @return an unmodifiable view of the specified collection.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
+        if (c.getClass() == UnmodifiableCollection.class) {
+            return (Collection<T>) c;
+        }
+        return new UnmodifiableCollection<>(c);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 1820017752578914078L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Collection<? extends E> c;
+
+        UnmodifiableCollection(Collection<? extends E> c) {
+            if (c==null)
+                throw new NullPointerException();
+            this.c = c;
+        }
+
+        public int size()                          {return c.size();}
+        public boolean isEmpty()                   {return c.isEmpty();}
+        public boolean contains(Object o)          {return c.contains(o);}
+        public Object[] toArray()                  {return c.toArray();}
+        public <T> T[] toArray(T[] a)              {return c.toArray(a);}
+        public <T> T[] toArray(IntFunction<T[]> f) {return c.toArray(f);}
+        public String toString()                   {return c.toString();}
+
+        public Iterator<E> iterator() {
+            return new Iterator<>() {
+                private final Iterator<? extends E> i = c.iterator();
+
+                public boolean hasNext() {return i.hasNext();}
+                public E next()          {return i.next();}
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    // Use backing collection version
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public boolean add(E e) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean removeAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean retainAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            c.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Spliterator<E> spliterator() {
+            return (Spliterator<E>)c.spliterator();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> stream() {
+            return (Stream<E>)c.stream();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> parallelStream() {
+            return (Stream<E>)c.parallelStream();
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified {@code SequencedCollection}. Query operations on the returned collection
+     * "read through" to the specified collection, and attempts to modify the returned
+     * collection, whether direct or via its iterator, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned collection does <i>not</i> pass the {@code hashCode} and
+     * {@code equals} operations through to the backing collection, but relies on
+     * {@code Object}'s {@code equals} and {@code hashCode} methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection for which an unmodifiable view is to be
+     *         returned.
+     * @return an unmodifiable view of the specified collection.
+     * @since 21
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> SequencedCollection<T> unmodifiableSequencedCollection(SequencedCollection<? extends T> c) {
+        if (c.getClass() == UnmodifiableSequencedCollection.class) {
+            return (SequencedCollection<T>) c;
+        }
+        return new UnmodifiableSequencedCollection<>(c);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSequencedCollection<E> extends UnmodifiableCollection<E>
+            implements SequencedCollection<E>, Serializable {
+
+        @java.io.Serial
+        private static final long serialVersionUID = -6060065079711684830L;
+
+        UnmodifiableSequencedCollection(SequencedCollection<? extends E> c) {
+            super(c);
+        }
+
+        @SuppressWarnings("unchecked")
+        private SequencedCollection<E> sc() {
+            return (SequencedCollection<E>) c;
+        }
+
+        // Even though this wrapper class is serializable, the reversed view is effectively
+        // not serializable because it points to the reversed collection view, which usually isn't
+        // serializable.
+        public SequencedCollection<E> reversed() {
+            return new UnmodifiableSequencedCollection<>(sc().reversed());
+        }
+
+        public void addFirst(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void addLast(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        public E getFirst() {
+            return sc().getFirst();
+        }
+
+        public E getLast() {
+            return sc().getLast();
+        }
+
+        public E removeFirst() {
+            throw new UnsupportedOperationException();
+        }
+
+        public E removeLast() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified set. Query operations on the returned set "read through" to the specified
+     * set, and attempts to modify the returned set, whether direct or via its
+     * iterator, result in an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned set will be serializable if the specified set
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the set
+     * @param  s the set for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified set.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Set<T> unmodifiableSet(Set<? extends T> s) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (s.getClass() == UnmodifiableSet.class) {
+            return (Set<T>) s;
+        }
+        return new UnmodifiableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
+                                 implements Set<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -9215047833775013803L;
+
+        UnmodifiableSet(Set<? extends E> s)     {super(s);}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified {@code SequencedSet}. Query operations on the returned set
+     * "read through" to the specified set, and attempts to modify the returned
+     * set, whether direct or via its iterator, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned set will be serializable if the specified set
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the set
+     * @param  s the set for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified sequenced set.
+     * @since 21
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> SequencedSet<T> unmodifiableSequencedSet(SequencedSet<? extends T> s) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (s.getClass() == UnmodifiableSequencedSet.class) {
+            return (SequencedSet<T>) s;
+        }
+        return new UnmodifiableSequencedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSequencedSet<E> extends UnmodifiableSequencedCollection<E>
+                                             implements SequencedSet<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -2153469532349793522L;
+
+        UnmodifiableSequencedSet(SequencedSet<? extends E> s)    {super(s);}
+        public boolean equals(Object o)                          {return o == this || c.equals(o);}
+        public int hashCode()                                    {return c.hashCode();}
+
+        @SuppressWarnings("unchecked")
+        private SequencedSet<E> ss() {
+            return (SequencedSet<E>) c;
+        }
+
+        // Even though this wrapper class is serializable, the reversed view is effectively
+        // not serializable because it points to the reversed set view, which usually isn't
+        // serializable.
+        public SequencedSet<E> reversed() {
+            return new UnmodifiableSequencedSet<>(ss().reversed());
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified sorted set. Query operations on the returned sorted set "read
+     * through" to the specified sorted set.  Attempts to modify the returned
+     * sorted set, whether direct, via its iterator, or via its
+     * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned sorted set will be serializable if the specified sorted set
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the set
+     * @param s the sorted set for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (s.getClass() == UnmodifiableSortedSet.class) {
+            return s;
+        }
+        return new UnmodifiableSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedSet<E>
+                             extends UnmodifiableSet<E>
+                             implements SortedSet<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -4929149591599911165L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedSet<E> ss;
+
+        UnmodifiableSortedSet(SortedSet<E> s) {super(s); ss = s;}
+
+        public Comparator<? super E> comparator() {return ss.comparator();}
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement));
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return new UnmodifiableSortedSet<>(ss.headSet(toElement));
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return new UnmodifiableSortedSet<>(ss.tailSet(fromElement));
+        }
+
+        public E first()                   {return ss.first();}
+        public E last()                    {return ss.last();}
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified navigable set. Query operations on the returned navigable set "read
+     * through" to the specified navigable set.  Attempts to modify the returned
+     * navigable set, whether direct, via its iterator, or via its
+     * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the set
+     * @param s the navigable set for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) {
+        if (s.getClass() == UnmodifiableNavigableSet.class) {
+            return s;
+        }
+        return new UnmodifiableNavigableSet<>(s);
+    }
+
+    /**
+     * Wraps a navigable set and disables all of the mutative operations.
+     *
+     * @param <E> type of elements
+     * @serial include
+     */
+    static class UnmodifiableNavigableSet<E>
+                             extends UnmodifiableSortedSet<E>
+                             implements NavigableSet<E>, Serializable {
+
+        @java.io.Serial
+        private static final long serialVersionUID = -6027448201786391929L;
+
+        /**
+         * A singleton empty unmodifiable navigable set used for
+         * {@link #emptyNavigableSet()}.
+         *
+         * @param <E> type of elements, if there were any, and bounds
+         */
+        private static class EmptyNavigableSet<E> extends UnmodifiableNavigableSet<E>
+            implements Serializable {
+            @java.io.Serial
+            private static final long serialVersionUID = -6291252904449939134L;
+
+            public EmptyNavigableSet() {
+                super(new TreeSet<>());
+            }
+
+            @java.io.Serial
+            private Object readResolve()        { return EMPTY_NAVIGABLE_SET; }
+        }
+
+        private static final NavigableSet<?> EMPTY_NAVIGABLE_SET =
+                new EmptyNavigableSet<>();
+
+        /**
+         * The instance we are protecting.
+         */
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableSet<E> ns;
+
+        UnmodifiableNavigableSet(NavigableSet<E> s)         {super(s); ns = s;}
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()     { throw new UnsupportedOperationException(); }
+        public E pollLast()      { throw new UnsupportedOperationException(); }
+        public NavigableSet<E> descendingSet()
+                 { return new UnmodifiableNavigableSet<>(ns.descendingSet()); }
+        public Iterator<E> descendingIterator()
+                                         { return descendingSet().iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.headSet(toElement, inclusive));
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.tailSet(fromElement, inclusive));
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified list. Query operations on the returned list "read through" to the
+     * specified list, and attempts to modify the returned list, whether
+     * direct or via its iterator, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned list will be serializable if the specified list
+     * is serializable. Similarly, the returned list will implement
+     * {@link RandomAccess} if the specified list does.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param  <T> the class of the objects in the list
+     * @param  list the list for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified list.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> unmodifiableList(List<? extends T> list) {
+        if (list.getClass() == UnmodifiableList.class || list.getClass() == UnmodifiableRandomAccessList.class) {
+           return (List<T>) list;
+        }
+
+        return (list instanceof RandomAccess ?
+                new UnmodifiableRandomAccessList<>(list) :
+                new UnmodifiableList<>(list));
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
+                                  implements List<E> {
+        @java.io.Serial
+        private static final long serialVersionUID = -283967356065247728L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final List<? extends E> list;
+
+        UnmodifiableList(List<? extends E> list) {
+            super(list);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {return o == this || list.equals(o);}
+        public int hashCode()           {return list.hashCode();}
+
+        public E get(int index) {return list.get(index);}
+        public E set(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public void add(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public E remove(int index) {
+            throw new UnsupportedOperationException();
+        }
+        public int indexOf(Object o)            {return list.indexOf(o);}
+        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
+        public boolean addAll(int index, Collection<? extends E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public ListIterator<E> listIterator()   {return listIterator(0);}
+
+        public ListIterator<E> listIterator(final int index) {
+            return new ListIterator<>() {
+                private final ListIterator<? extends E> i
+                    = list.listIterator(index);
+
+                public boolean hasNext()     {return i.hasNext();}
+                public E next()              {return i.next();}
+                public boolean hasPrevious() {return i.hasPrevious();}
+                public E previous()          {return i.previous();}
+                public int nextIndex()       {return i.nextIndex();}
+                public int previousIndex()   {return i.previousIndex();}
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                public void set(E e) {
+                    throw new UnsupportedOperationException();
+                }
+                public void add(E e) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableList<>(list.subList(fromIndex, toIndex));
+        }
+
+        /**
+         * UnmodifiableRandomAccessList instances are serialized as
+         * UnmodifiableList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * UnmodifiableList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, UnmodifiableRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * UnmodifiableList instances, as this method was missing in 1.4.
+         */
+        @java.io.Serial
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new UnmodifiableRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E>
+                                              implements RandomAccess
+    {
+        UnmodifiableRandomAccessList(List<? extends E> list) {
+            super(list);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableRandomAccessList<>(
+                list.subList(fromIndex, toIndex));
+        }
+
+        @java.io.Serial
+        private static final long serialVersionUID = -2542308836966382001L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have UnmodifiableRandomAccessList).  UnmodifiableList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        @java.io.Serial
+        private Object writeReplace() {
+            return new UnmodifiableList<>(list);
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified map. Query operations on the returned map "read through"
+     * to the specified map, and attempts to modify the returned
+     * map, whether direct or via its collection views, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned map will be serializable if the specified map
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified map.
+     */
+    @SuppressWarnings("unchecked")
+    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (m.getClass() == UnmodifiableMap.class) {
+            return (Map<K,V>) m;
+        }
+        return new UnmodifiableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -1034234728574286014L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Map<? extends K, ? extends V> m;
+
+        UnmodifiableMap(Map<? extends K, ? extends V> m) {
+            if (m==null)
+                throw new NullPointerException();
+            this.m = m;
+        }
+
+        public int size()                        {return m.size();}
+        public boolean isEmpty()                 {return m.isEmpty();}
+        public boolean containsKey(Object key)   {return m.containsKey(key);}
+        public boolean containsValue(Object val) {return m.containsValue(val);}
+        public V get(Object key)                 {return m.get(key);}
+
+        public V put(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+        public V remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+        public void putAll(Map<? extends K, ? extends V> m) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = unmodifiableSet(m.keySet());
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new UnmodifiableEntrySet<>(m.entrySet());
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = unmodifiableCollection(m.values());
+            return values;
+        }
+
+        public boolean equals(Object o) {return o == this || m.equals(o);}
+        public int hashCode()           {return m.hashCode();}
+        public String toString()        {return m.toString();}
+
+        // Override default methods in Map
+        @Override
+        @SuppressWarnings("unchecked")
+        public V getOrDefault(Object k, V defaultValue) {
+            // Safe cast as we don't change the value
+            return ((Map<K, V>)m).getOrDefault(k, defaultValue);
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * We need this class in addition to UnmodifiableSet as
+         * Map.Entries themselves permit modification of the backing Map
+         * via their setValue operation.  This class is subtle: there are
+         * many possible attacks that must be thwarted.
+         *
+         * @serial include
+         */
+        static class UnmodifiableEntrySet<K,V>
+            extends UnmodifiableSet<Map.Entry<K,V>> {
+            @java.io.Serial
+            private static final long serialVersionUID = 7854390611657943733L;
+
+            @SuppressWarnings({"unchecked"})
+            UnmodifiableEntrySet(Set<? extends Map.Entry<? extends K, ? extends V>> s) {
+                super((Set<Map.Entry<K, V>>)s);
+            }
+
+            static <K, V> Consumer<Map.Entry<? extends K, ? extends V>> entryConsumer(
+                    Consumer<? super Entry<K, V>> action) {
+                return e -> action.accept(new UnmodifiableEntry<>(e));
+            }
+
+            public void forEach(Consumer<? super Entry<K, V>> action) {
+                Objects.requireNonNull(action);
+                c.forEach(entryConsumer(action));
+            }
+
+            static final class UnmodifiableEntrySetSpliterator<K, V>
+                    implements Spliterator<Entry<K,V>> {
+                final Spliterator<Map.Entry<K, V>> s;
+
+                UnmodifiableEntrySetSpliterator(Spliterator<Entry<K, V>> s) {
+                    this.s = s;
+                }
+
+                @Override
+                public boolean tryAdvance(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    return s.tryAdvance(entryConsumer(action));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    s.forEachRemaining(entryConsumer(action));
+                }
+
+                @Override
+                public Spliterator<Entry<K, V>> trySplit() {
+                    Spliterator<Entry<K, V>> split = s.trySplit();
+                    return split == null
+                           ? null
+                           : new UnmodifiableEntrySetSpliterator<>(split);
+                }
+
+                @Override
+                public long estimateSize() {
+                    return s.estimateSize();
+                }
+
+                @Override
+                public long getExactSizeIfKnown() {
+                    return s.getExactSizeIfKnown();
+                }
+
+                @Override
+                public int characteristics() {
+                    return s.characteristics();
+                }
+
+                @Override
+                public boolean hasCharacteristics(int characteristics) {
+                    return s.hasCharacteristics(characteristics);
+                }
+
+                @Override
+                public Comparator<? super Entry<K, V>> getComparator() {
+                    return s.getComparator();
+                }
+            }
+
+            @SuppressWarnings("unchecked")
+            public Spliterator<Entry<K,V>> spliterator() {
+                return new UnmodifiableEntrySetSpliterator<>(
+                        (Spliterator<Map.Entry<K, V>>) c.spliterator());
+            }
+
+            @Override
+            public Stream<Entry<K,V>> stream() {
+                return StreamSupport.stream(spliterator(), false);
+            }
+
+            @Override
+            public Stream<Entry<K,V>> parallelStream() {
+                return StreamSupport.stream(spliterator(), true);
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new Iterator<>() {
+                    private final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();
+
+                    public boolean hasNext() {
+                        return i.hasNext();
+                    }
+                    public Map.Entry<K,V> next() {
+                        return new UnmodifiableEntry<>(i.next());
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                    // Seems like an oversight. http://b/110351017
+                    public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+                        Objects.requireNonNull(action);
+                        i.forEachRemaining(entryConsumer(action));
+                    }
+                };
+            }
+
+            @SuppressWarnings("unchecked")
+            public Object[] toArray() {
+                Object[] a = c.toArray();
+                for (int i=0; i<a.length; i++)
+                    a[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)a[i]);
+                return a;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to c.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from c.
+                Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)arr[i]);
+
+                if (arr.length > a.length)
+                    return (T[])arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return c.contains(
+                    new UnmodifiableEntry<>((Map.Entry<?,?>) o));
+            }
+
+            /**
+             * The next two methods are overridden to protect against
+             * an unscrupulous List whose contains(Object o) method senses
+             * when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> coll) {
+                for (Object e : coll) {
+                    if (!contains(e)) // Invokes safe contains() above
+                        return false;
+                }
+                return true;
+            }
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+
+                // Android-changed: (b/247094511) instanceof pattern variable is not yet supported.
+                /*
+                return o instanceof Set<?> s
+                        && s.size() == c.size()
+                        && containsAll(s); // Invokes safe containsAll() above
+                 */
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> s = (Set<?>) o;
+                if (s.size() != c.size())
+                    return false;
+                return containsAll(s); // Invokes safe containsAll() above
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map Entry when asked to perform an equality check.
+             */
+            private static class UnmodifiableEntry<K,V> implements Map.Entry<K,V> {
+                private Map.Entry<? extends K, ? extends V> e;
+
+                UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e)
+                        {this.e = Objects.requireNonNull(e);}
+
+                public K getKey()        {return e.getKey();}
+                public V getValue()      {return e.getValue();}
+                public V setValue(V value) {
+                    throw new UnsupportedOperationException();
+                }
+                public int hashCode()    {return e.hashCode();}
+                public boolean equals(Object o) {
+                    if (this == o)
+                        return true;
+                    // Android-changed: (b/247094511) instanceof pattern variable is not yet
+                    // supported.
+                    /*
+                    return o instanceof Map.Entry<?, ?> t
+                            && eq(e.getKey(),   t.getKey())
+                            && eq(e.getValue(), t.getValue());
+                    */
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    Map.Entry<?,?> t = (Map.Entry<?,?>)o;
+                    return eq(e.getKey(),   t.getKey()) &&
+                            eq(e.getValue(), t.getValue());
+                }
+                public String toString() {return e.toString();}
+            }
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified {@code SequencedMap}. Query operations on the returned map
+     * "read through" to the specified map, and attempts to modify the returned
+     * map, whether direct or via its collection views, result in an
+     * {@code UnsupportedOperationException}.<p>
+     *
+     * The returned map will be serializable if the specified map
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified map.
+     * @since 21
+     */
+    @SuppressWarnings("unchecked")
+    public static <K,V> SequencedMap<K,V> unmodifiableSequencedMap(SequencedMap<? extends K, ? extends V> m) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (m.getClass() == UnmodifiableSequencedMap.class) {
+            return (SequencedMap<K,V>) m;
+        }
+        return new UnmodifiableSequencedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class UnmodifiableSequencedMap<K,V> extends UnmodifiableMap<K,V> implements SequencedMap<K,V>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -8171676257373950636L;
+
+        UnmodifiableSequencedMap(Map<? extends K, ? extends V> m) {
+            super(m);
+        }
+
+        @SuppressWarnings("unchecked")
+        private SequencedMap<K, V> sm() {
+            return (SequencedMap<K, V>) m;
+        }
+
+        // Even though this wrapper class is serializable, the reversed view is effectively
+        // not serializable because it points to the reversed map view, which usually isn't
+        // serializable.
+        public SequencedMap<K, V> reversed() {
+            return new UnmodifiableSequencedMap<>(sm().reversed());
+        }
+
+        public Entry<K, V> pollFirstEntry() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Entry<K, V> pollLastEntry() {
+            throw new UnsupportedOperationException();
+        }
+
+        public V putFirst(K k, V v) {
+            throw new UnsupportedOperationException();
+        }
+
+        public V putLast(K k, V v) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified sorted map. Query operations on the returned sorted map "read through"
+     * to the specified sorted map.  Attempts to modify the returned
+     * sorted map, whether direct, via its collection views, or via its
+     * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned sorted map will be serializable if the specified sorted map
+     * is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the sorted map for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted map.
+     */
+    @SuppressWarnings("unchecked")
+    public static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K, ? extends V> m) {
+        // Not checking for subclasses because of heap pollution and information leakage.
+        if (m.getClass() == UnmodifiableSortedMap.class) {
+            return (SortedMap<K,V>) m;
+        }
+        return new UnmodifiableSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedMap<K,V>
+          extends UnmodifiableMap<K,V>
+          implements SortedMap<K,V>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -8806743815996713206L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedMap<K, ? extends V> sm;
+
+        UnmodifiableSortedMap(SortedMap<K, ? extends V> m) {super(m); sm = m; }
+        public Comparator<? super K> comparator()   { return sm.comparator(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey)
+             { return new UnmodifiableSortedMap<>(sm.subMap(fromKey, toKey)); }
+        public SortedMap<K,V> headMap(K toKey)
+                     { return new UnmodifiableSortedMap<>(sm.headMap(toKey)); }
+        public SortedMap<K,V> tailMap(K fromKey)
+                   { return new UnmodifiableSortedMap<>(sm.tailMap(fromKey)); }
+        public K firstKey()                           { return sm.firstKey(); }
+        public K lastKey()                             { return sm.lastKey(); }
+    }
+
+    /**
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified navigable map. Query operations on the returned navigable map "read
+     * through" to the specified navigable map.  Attempts to modify the returned
+     * navigable map, whether direct, via its collection views, or via its
+     * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @implNote This method may return its argument if the argument is already unmodifiable.
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the navigable map for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <K,V> NavigableMap<K,V> unmodifiableNavigableMap(NavigableMap<K, ? extends V> m) {
+        if (m.getClass() == UnmodifiableNavigableMap.class) {
+            return (NavigableMap<K,V>) m;
+        }
+        return new UnmodifiableNavigableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableNavigableMap<K,V>
+          extends UnmodifiableSortedMap<K,V>
+          implements NavigableMap<K,V>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -4858195264774772197L;
+
+        /**
+         * A class for the {@link #EMPTY_NAVIGABLE_MAP} which needs readResolve
+         * to preserve singleton property.
+         *
+         * @param <K> type of keys, if there were any, and of bounds
+         * @param <V> type of values, if there were any
+         */
+        private static class EmptyNavigableMap<K,V> extends UnmodifiableNavigableMap<K,V>
+            implements Serializable {
+
+            @java.io.Serial
+            private static final long serialVersionUID = -2239321462712562324L;
+
+            EmptyNavigableMap()                       { super(new TreeMap<>()); }
+
+            @Override
+            public NavigableSet<K> navigableKeySet()
+                                                { return emptyNavigableSet(); }
+
+            @java.io.Serial
+            private Object readResolve()        { return EMPTY_NAVIGABLE_MAP; }
+        }
+
+        /**
+         * Singleton for {@link #emptyNavigableMap()} which is also immutable.
+         */
+        private static final EmptyNavigableMap<?,?> EMPTY_NAVIGABLE_MAP =
+            new EmptyNavigableMap<>();
+
+        /**
+         * The instance we wrap and protect.
+         */
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableMap<K, ? extends V> nm;
+
+        UnmodifiableNavigableMap(NavigableMap<K, ? extends V> m)
+                                                            {super(m); nm = m;}
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = (Entry<K, V>) nm.lowerEntry(key);
+            return (null != lower)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(lower)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = (Entry<K, V>) nm.floorEntry(key);
+            return (null != floor)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(floor)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = (Entry<K, V>) nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(ceiling)
+                : null;
+        }
+
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = (Entry<K, V>) nm.higherEntry(key);
+            return (null != higher)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(higher)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = (Entry<K, V>) nm.firstEntry();
+            return (null != first)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(first)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = (Entry<K, V>) nm.lastEntry();
+            return (null != last)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(last)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public Entry<K, V> pollLastEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public NavigableMap<K, V> descendingMap()
+                       { return unmodifiableNavigableMap(nm.descendingMap()); }
+        public NavigableSet<K> navigableKeySet()
+                     { return unmodifiableNavigableSet(nm.navigableKeySet()); }
+        public NavigableSet<K> descendingKeySet()
+                    { return unmodifiableNavigableSet(nm.descendingKeySet()); }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return unmodifiableNavigableMap(
+                nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive)
+             { return unmodifiableNavigableMap(nm.headMap(toKey, inclusive)); }
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive)
+           { return unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive)); }
+    }
+
+    // Synch Wrappers
+
+    /**
+     * Returns a synchronized (thread-safe) collection backed by the specified
+     * collection.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing collection is accomplished
+     * through the returned collection.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * collection when traversing it via {@link Iterator}, {@link Spliterator}
+     * or {@link Stream}:
+     * <pre>
+     *  Collection c = Collections.synchronizedCollection(myCollection);
+     *     ...
+     *  synchronized (c) {
+     *      Iterator i = c.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *         foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned collection does <i>not</i> pass the {@code hashCode}
+     * and {@code equals} operations through to the backing collection, but
+     * relies on {@code Object}'s equals and hashCode methods.  This is
+     * necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection to be "wrapped" in a synchronized collection.
+     * @return a synchronized view of the specified collection.
+     */
+    public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
+        return new SynchronizedCollection<>(c);
+    }
+
+    static <T> Collection<T> synchronizedCollection(Collection<T> c, Object mutex) {
+        return new SynchronizedCollection<>(c, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 3053995032091335093L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Collection<E> c;  // Backing Collection
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Object mutex;     // Object on which to synchronize
+
+        SynchronizedCollection(Collection<E> c) {
+            this.c = Objects.requireNonNull(c);
+            mutex = this;
+        }
+
+        SynchronizedCollection(Collection<E> c, Object mutex) {
+            this.c = Objects.requireNonNull(c);
+            this.mutex = Objects.requireNonNull(mutex);
+        }
+
+        public int size() {
+            synchronized (mutex) {return c.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return c.isEmpty();}
+        }
+        public boolean contains(Object o) {
+            synchronized (mutex) {return c.contains(o);}
+        }
+        public Object[] toArray() {
+            synchronized (mutex) {return c.toArray();}
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (mutex) {return c.toArray(a);}
+        }
+        public <T> T[] toArray(IntFunction<T[]> f) {
+            synchronized (mutex) {return c.toArray(f);}
+        }
+
+        public Iterator<E> iterator() {
+            return c.iterator(); // Must be manually synched by user!
+        }
+
+        public boolean add(E e) {
+            synchronized (mutex) {return c.add(e);}
+        }
+        public boolean remove(Object o) {
+            synchronized (mutex) {return c.remove(o);}
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            synchronized (mutex) {return c.containsAll(coll);}
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            synchronized (mutex) {return c.addAll(coll);}
+        }
+        public boolean removeAll(Collection<?> coll) {
+            synchronized (mutex) {return c.removeAll(coll);}
+        }
+        public boolean retainAll(Collection<?> coll) {
+            synchronized (mutex) {return c.retainAll(coll);}
+        }
+        public void clear() {
+            synchronized (mutex) {c.clear();}
+        }
+        public String toString() {
+            synchronized (mutex) {return c.toString();}
+        }
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> consumer) {
+            synchronized (mutex) {c.forEach(consumer);}
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            synchronized (mutex) {return c.removeIf(filter);}
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return c.spliterator(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
+        @java.io.Serial
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) set backed by the specified
+     * set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing set is accomplished
+     * through the returned set.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * collection when traversing it via {@link Iterator}, {@link Spliterator}
+     * or {@link Stream}:
+     * <pre>
+     *  Set s = Collections.synchronizedSet(new HashSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the set to be "wrapped" in a synchronized set.
+     * @return a synchronized view of the specified set.
+     */
+    public static <T> Set<T> synchronizedSet(Set<T> s) {
+        return new SynchronizedSet<>(s);
+    }
+
+    static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
+        return new SynchronizedSet<>(s, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSet<E>
+          extends SynchronizedCollection<E>
+          implements Set<E> {
+        @java.io.Serial
+        private static final long serialVersionUID = 487447009682186044L;
+
+        SynchronizedSet(Set<E> s) {
+            super(s);
+        }
+        SynchronizedSet(Set<E> s, Object mutex) {
+            super(s, mutex);
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return c.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return c.hashCode();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted set backed by the specified
+     * sorted set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted set is accomplished
+     * through the returned sorted set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted set when traversing it or any of its {@code subSet},
+     * {@code headSet}, or {@code tailSet} views via {@link Iterator},
+     * {@link Spliterator} or {@link Stream}:
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *  SortedSet s2 = s.headSet(foo);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted set will be serializable if the specified
+     * sorted set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the sorted set to be "wrapped" in a synchronized sorted set.
+     * @return a synchronized view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) {
+        return new SynchronizedSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedSet<E>
+        extends SynchronizedSet<E>
+        implements SortedSet<E>
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 8695801310862127406L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedSet<E> ss;
+
+        SynchronizedSortedSet(SortedSet<E> s) {
+            super(s);
+            ss = s;
+        }
+        SynchronizedSortedSet(SortedSet<E> s, Object mutex) {
+            super(s, mutex);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() {
+            synchronized (mutex) {return ss.comparator();}
+        }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(
+                    ss.subSet(fromElement, toElement), mutex);
+            }
+        }
+        public SortedSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex);
+            }
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+               return new SynchronizedSortedSet<>(ss.tailSet(fromElement),mutex);
+            }
+        }
+
+        public E first() {
+            synchronized (mutex) {return ss.first();}
+        }
+        public E last() {
+            synchronized (mutex) {return ss.last();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable set backed by the
+     * specified navigable set.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable set is
+     * accomplished through the returned navigable set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable set when traversing it, or any of its {@code subSet},
+     * {@code headSet}, or {@code tailSet} views, via {@link Iterator},
+     * {@link Spliterator} or {@link Stream}:
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *  NavigableSet s2 = s.headSet(foo, true);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the navigable set to be "wrapped" in a synchronized navigable
+     * set
+     * @return a synchronized view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s) {
+        return new SynchronizedNavigableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedNavigableSet<E>
+        extends SynchronizedSortedSet<E>
+        implements NavigableSet<E>
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -5505529816273629798L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableSet<E> ns;
+
+        SynchronizedNavigableSet(NavigableSet<E> s) {
+            super(s);
+            ns = s;
+        }
+
+        SynchronizedNavigableSet(NavigableSet<E> s, Object mutex) {
+            super(s, mutex);
+            ns = s;
+        }
+        public E lower(E e)      { synchronized (mutex) {return ns.lower(e);} }
+        public E floor(E e)      { synchronized (mutex) {return ns.floor(e);} }
+        public E ceiling(E e)  { synchronized (mutex) {return ns.ceiling(e);} }
+        public E higher(E e)    { synchronized (mutex) {return ns.higher(e);} }
+        public E pollFirst()  { synchronized (mutex) {return ns.pollFirst();} }
+        public E pollLast()    { synchronized (mutex) {return ns.pollLast();} }
+
+        public NavigableSet<E> descendingSet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex);
+            }
+        }
+
+        public Iterator<E> descendingIterator()
+                 { synchronized (mutex) { return descendingSet().iterator(); } }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, true, toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, true), mutex);
+            }
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive), mutex);
+            }
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) list backed by the specified
+     * list.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing list is accomplished
+     * through the returned list.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * list when traversing it via {@link Iterator}, {@link Spliterator}
+     * or {@link Stream}:
+     * <pre>
+     *  List list = Collections.synchronizedList(new ArrayList());
+     *      ...
+     *  synchronized (list) {
+     *      Iterator i = list.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned list will be serializable if the specified list is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be "wrapped" in a synchronized list.
+     * @return a synchronized view of the specified list.
+     */
+    public static <T> List<T> synchronizedList(List<T> list) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list) :
+                new SynchronizedList<>(list));
+    }
+
+    static <T> List<T> synchronizedList(List<T> list, Object mutex) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list, mutex) :
+                new SynchronizedList<>(list, mutex));
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedList<E>
+        extends SynchronizedCollection<E>
+        implements List<E> {
+        @java.io.Serial
+        private static final long serialVersionUID = -7754090372962971524L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final List<E> list;
+
+        SynchronizedList(List<E> list) {
+            super(list);
+            this.list = list;
+        }
+        SynchronizedList(List<E> list, Object mutex) {
+            super(list, mutex);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return list.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return list.hashCode();}
+        }
+
+        public E get(int index) {
+            synchronized (mutex) {return list.get(index);}
+        }
+        public E set(int index, E element) {
+            synchronized (mutex) {return list.set(index, element);}
+        }
+        public void add(int index, E element) {
+            synchronized (mutex) {list.add(index, element);}
+        }
+        public E remove(int index) {
+            synchronized (mutex) {return list.remove(index);}
+        }
+
+        public int indexOf(Object o) {
+            synchronized (mutex) {return list.indexOf(o);}
+        }
+        public int lastIndexOf(Object o) {
+            synchronized (mutex) {return list.lastIndexOf(o);}
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (mutex) {return list.addAll(index, c);}
+        }
+
+        public ListIterator<E> listIterator() {
+            return list.listIterator(); // Must be manually synched by user
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            return list.listIterator(index); // Must be manually synched by user
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedList<>(list.subList(fromIndex, toIndex),
+                                            mutex);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            synchronized (mutex) {list.replaceAll(operator);}
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            synchronized (mutex) {list.sort(c);}
+        }
+
+        /**
+         * SynchronizedRandomAccessList instances are serialized as
+         * SynchronizedList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * SynchronizedList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, SynchronizedRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * SynchronizedList instances, as this method was missing in 1.4.
+         */
+        @java.io.Serial
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new SynchronizedRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedRandomAccessList<E>
+        extends SynchronizedList<E>
+        implements RandomAccess {
+
+        SynchronizedRandomAccessList(List<E> list) {
+            super(list);
+        }
+
+        SynchronizedRandomAccessList(List<E> list, Object mutex) {
+            super(list, mutex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), mutex);
+            }
+        }
+
+        @java.io.Serial
+        private static final long serialVersionUID = 1530674583602358482L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have SynchronizedRandomAccessList).  SynchronizedList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        @java.io.Serial
+        private Object writeReplace() {
+            return new SynchronizedList<>(list);
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) map backed by the specified
+     * map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing map is accomplished
+     * through the returned map.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * map when traversing any of its collection views via {@link Iterator},
+     * {@link Spliterator} or {@link Stream}:
+     * <pre>
+     *  Map m = Collections.synchronizedMap(new HashMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map to be "wrapped" in a synchronized map.
+     * @return a synchronized view of the specified map.
+     */
+    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
+        return new SynchronizedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SynchronizedMap<K,V>
+        implements Map<K,V>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 1978198479659022715L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final Map<K,V> m;     // Backing Map
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Object      mutex;        // Object on which to synchronize
+
+        SynchronizedMap(Map<K,V> m) {
+            this.m = Objects.requireNonNull(m);
+            mutex = this;
+        }
+
+        SynchronizedMap(Map<K,V> m, Object mutex) {
+            this.m = m;
+            this.mutex = mutex;
+        }
+
+        public int size() {
+            synchronized (mutex) {return m.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return m.isEmpty();}
+        }
+        public boolean containsKey(Object key) {
+            synchronized (mutex) {return m.containsKey(key);}
+        }
+        public boolean containsValue(Object value) {
+            synchronized (mutex) {return m.containsValue(value);}
+        }
+        public V get(Object key) {
+            synchronized (mutex) {return m.get(key);}
+        }
+
+        public V put(K key, V value) {
+            synchronized (mutex) {return m.put(key, value);}
+        }
+        public V remove(Object key) {
+            synchronized (mutex) {return m.remove(key);}
+        }
+        public void putAll(Map<? extends K, ? extends V> map) {
+            synchronized (mutex) {m.putAll(map);}
+        }
+        public void clear() {
+            synchronized (mutex) {m.clear();}
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            synchronized (mutex) {
+                if (keySet==null)
+                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
+                return keySet;
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            synchronized (mutex) {
+                if (entrySet==null)
+                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
+                return entrySet;
+            }
+        }
+
+        public Collection<V> values() {
+            synchronized (mutex) {
+                if (values==null)
+                    values = new SynchronizedCollection<>(m.values(), mutex);
+                return values;
+            }
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return m.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return m.hashCode();}
+        }
+        public String toString() {
+            synchronized (mutex) {return m.toString();}
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object k, V defaultValue) {
+            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
+        }
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            synchronized (mutex) {m.forEach(action);}
+        }
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            synchronized (mutex) {m.replaceAll(function);}
+        }
+        @Override
+        public V putIfAbsent(K key, V value) {
+            synchronized (mutex) {return m.putIfAbsent(key, value);}
+        }
+        @Override
+        public boolean remove(Object key, Object value) {
+            synchronized (mutex) {return m.remove(key, value);}
+        }
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
+        }
+        @Override
+        public V replace(K key, V value) {
+            synchronized (mutex) {return m.replace(key, value);}
+        }
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
+        }
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
+        }
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.compute(key, remappingFunction);}
+        }
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
+        }
+
+        @java.io.Serial
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted map backed by the specified
+     * sorted map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted map is accomplished
+     * through the returned sorted map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted map when traversing any of its collection views, or the
+     * collections views of any of its {@code subMap}, {@code headMap} or
+     * {@code tailMap} views, via {@link Iterator}, {@link Spliterator} or
+     * {@link Stream}:
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *  SortedMap m2 = m.subMap(foo, bar);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s2.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted map will be serializable if the specified
+     * sorted map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the sorted map to be "wrapped" in a synchronized sorted map.
+     * @return a synchronized view of the specified sorted map.
+     */
+    public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) {
+        return new SynchronizedSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedMap<K,V>
+        extends SynchronizedMap<K,V>
+        implements SortedMap<K,V>
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -8798146769416483793L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedMap<K,V> sm;
+
+        SynchronizedSortedMap(SortedMap<K,V> m) {
+            super(m);
+            sm = m;
+        }
+        SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() {
+            synchronized (mutex) {return sm.comparator();}
+        }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(
+                    sm.subMap(fromKey, toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+               return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex);
+            }
+        }
+
+        public K firstKey() {
+            synchronized (mutex) {return sm.firstKey();}
+        }
+        public K lastKey() {
+            synchronized (mutex) {return sm.lastKey();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable map backed by the
+     * specified navigable map.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable map is
+     * accomplished through the returned navigable map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable map when traversing any of its collection views, or the
+     * collections views of any of its {@code subMap}, {@code headMap} or
+     * {@code tailMap} views, via {@link Iterator}, {@link Spliterator} or
+     * {@link Stream}:
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *  NavigableMap m2 = m.subMap(foo, true, bar, false);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s2.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the navigable map to be "wrapped" in a synchronized navigable
+     *              map
+     * @return a synchronized view of the specified navigable map.
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m) {
+        return new SynchronizedNavigableMap<>(m);
+    }
+
+    /**
+     * A synchronized NavigableMap.
+     *
+     * @serial include
+     */
+    static class SynchronizedNavigableMap<K,V>
+        extends SynchronizedSortedMap<K,V>
+        implements NavigableMap<K,V>
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 699392247599746807L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableMap<K,V> nm;
+
+        SynchronizedNavigableMap(NavigableMap<K,V> m) {
+            super(m);
+            nm = m;
+        }
+        SynchronizedNavigableMap(NavigableMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            nm = m;
+        }
+
+        public Entry<K, V> lowerEntry(K key)
+                        { synchronized (mutex) { return nm.lowerEntry(key); } }
+        public K lowerKey(K key)
+                          { synchronized (mutex) { return nm.lowerKey(key); } }
+        public Entry<K, V> floorEntry(K key)
+                        { synchronized (mutex) { return nm.floorEntry(key); } }
+        public K floorKey(K key)
+                          { synchronized (mutex) { return nm.floorKey(key); } }
+        public Entry<K, V> ceilingEntry(K key)
+                      { synchronized (mutex) { return nm.ceilingEntry(key); } }
+        public K ceilingKey(K key)
+                        { synchronized (mutex) { return nm.ceilingKey(key); } }
+        public Entry<K, V> higherEntry(K key)
+                       { synchronized (mutex) { return nm.higherEntry(key); } }
+        public K higherKey(K key)
+                         { synchronized (mutex) { return nm.higherKey(key); } }
+        public Entry<K, V> firstEntry()
+                           { synchronized (mutex) { return nm.firstEntry(); } }
+        public Entry<K, V> lastEntry()
+                            { synchronized (mutex) { return nm.lastEntry(); } }
+        public Entry<K, V> pollFirstEntry()
+                       { synchronized (mutex) { return nm.pollFirstEntry(); } }
+        public Entry<K, V> pollLastEntry()
+                        { synchronized (mutex) { return nm.pollLastEntry(); } }
+
+        public NavigableMap<K, V> descendingMap() {
+            synchronized (mutex) {
+                return
+                    new SynchronizedNavigableMap<>(nm.descendingMap(), mutex);
+            }
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.navigableKeySet(), mutex);
+            }
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.descendingKeySet(), mutex);
+            }
+        }
+
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, true, toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(nm.headMap(toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+        return new SynchronizedNavigableMap<>(nm.tailMap(fromKey, true),mutex);
+            }
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                        nm.headMap(toKey, inclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.tailMap(fromKey, inclusive), mutex);
+            }
+        }
+    }
+
+    // Dynamically typesafe collection wrappers
+
+    /**
+     * Returns a dynamically typesafe view of the specified collection.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a collection
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the collection takes place through the view, it is
+     * <i>guaranteed</i> that the collection cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>The generics mechanism in the language provides compile-time
+     * (static) type checking, but it is possible to defeat this mechanism
+     * with unchecked casts.  Usually this is not a problem, as the compiler
+     * issues warnings on all such unchecked operations.  There are, however,
+     * times when static type checking alone is not sufficient.  For example,
+     * suppose a collection is passed to a third-party library and it is
+     * imperative that the library code not corrupt the collection by
+     * inserting an element of the wrong type.
+     *
+     * <p>Another use of dynamically typesafe views is debugging.  Suppose a
+     * program fails with a {@code ClassCastException}, indicating that an
+     * incorrectly typed element was put into a parameterized collection.
+     * Unfortunately, the exception can occur at any time after the erroneous
+     * element is inserted, so it typically provides little or no information
+     * as to the real source of the problem.  If the problem is reproducible,
+     * one can quickly determine its source by temporarily modifying the
+     * program to wrap the collection with a dynamically typesafe view.
+     * For example, this declaration:
+     *  <pre> {@code
+     *     Collection<String> c = new HashSet<>();
+     * }</pre>
+     * may be replaced temporarily by this one:
+     *  <pre> {@code
+     *     Collection<String> c = Collections.checkedCollection(
+     *         new HashSet<>(), String.class);
+     * }</pre>
+     * Running the program again will cause it to fail at the point where
+     * an incorrectly typed element is inserted into the collection, clearly
+     * identifying the source of the problem.  Once the problem is fixed, the
+     * modified declaration may be reverted back to the original.
+     *
+     * <p>The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * {@code Object}'s {@code equals} and {@code hashCode} methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.
+     *
+     * <p>The returned collection will be serializable if the specified
+     * collection is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned collection permits insertion of null elements
+     * whenever the backing collection does.
+     *
+     * @param <E> the class of the objects in the collection
+     * @param c the collection for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code c} is permitted to hold
+     * @return a dynamically typesafe view of the specified collection
+     * @since 1.5
+     */
+    public static <E> Collection<E> checkedCollection(Collection<E> c,
+                                                      Class<E> type) {
+        return new CheckedCollection<>(c, type);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T> T[] zeroLengthArray(Class<T> type) {
+        return (T[]) Array.newInstance(type, 0);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedCollection<E> implements Collection<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 1578914078182001775L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Collection<E> c;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Class<E> type;
+
+        @SuppressWarnings("unchecked")
+        E typeCheck(Object o) {
+            if (o != null && !type.isInstance(o))
+                throw new ClassCastException(badElementMsg(o));
+            return (E) o;
+        }
+
+        private String badElementMsg(Object o) {
+            return "Attempt to insert " + o.getClass() +
+                " element into collection with element type " + type;
+        }
+
+        CheckedCollection(Collection<E> c, Class<E> type) {
+            this.c = Objects.requireNonNull(c, "c");
+            this.type = Objects.requireNonNull(type, "type");
+        }
+
+        public int size()                          { return c.size(); }
+        public boolean isEmpty()                   { return c.isEmpty(); }
+        public boolean contains(Object o)          { return c.contains(o); }
+        public Object[] toArray()                  { return c.toArray(); }
+        public <T> T[] toArray(T[] a)              { return c.toArray(a); }
+        public <T> T[] toArray(IntFunction<T[]> f) { return c.toArray(f); }
+        public String toString()                   { return c.toString(); }
+        public boolean remove(Object o)            { return c.remove(o); }
+        public void clear()                        {        c.clear(); }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean removeAll(Collection<?> coll) {
+            return c.removeAll(coll);
+        }
+        public boolean retainAll(Collection<?> coll) {
+            return c.retainAll(coll);
+        }
+
+        public Iterator<E> iterator() {
+            // JDK-6363904 - unwrapped iterator could be typecast to
+            // ListIterator with unsafe set()
+            final Iterator<E> it = c.iterator();
+            return new Iterator<>() {
+                public boolean hasNext() { return it.hasNext(); }
+                public E next()          { return it.next(); }
+                public void remove()     {        it.remove(); }
+                public void forEachRemaining(Consumer<? super E> action) {
+                    it.forEachRemaining(action);
+                }
+            };
+        }
+
+        public boolean add(E e)          { return c.add(typeCheck(e)); }
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private E[] zeroLengthElementArray; // Lazily initialized
+
+        private E[] zeroLengthElementArray() {
+            return zeroLengthElementArray != null ? zeroLengthElementArray :
+                (zeroLengthElementArray = zeroLengthArray(type));
+        }
+
+        @SuppressWarnings("unchecked")
+        Collection<E> checkedCopyOf(Collection<? extends E> coll) {
+            Object[] a;
+            try {
+                E[] z = zeroLengthElementArray();
+                a = coll.toArray(z);
+                // Defend against coll violating the toArray contract
+                if (a.getClass() != z.getClass())
+                    a = Arrays.copyOf(a, a.length, z.getClass());
+            } catch (ArrayStoreException ignore) {
+                // To get better and consistent diagnostics,
+                // we call typeCheck explicitly on each element.
+                // We call clone() to defend against coll retaining a
+                // reference to the returned array and storing a bad
+                // element into it after it has been type checked.
+                a = coll.toArray().clone();
+                for (Object o : a)
+                    typeCheck(o);
+            }
+            // A slight abuse of the type system, but safe here.
+            return (Collection<E>) Arrays.asList(a);
+        }
+
+        public boolean addAll(Collection<? extends E> coll) {
+            // Doing things this way insulates us from concurrent changes
+            // in the contents of coll and provides all-or-nothing
+            // semantics (which we wouldn't get if we type-checked each
+            // element as we added it)
+            return c.addAll(checkedCopyOf(coll));
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {c.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return c.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return c.spliterator();}
+        @Override
+        public Stream<E> stream()           {return c.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return c.parallelStream();}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified queue.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a queue contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the queue
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * queue cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned queue will be serializable if the specified queue
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned queue permits insertion of {@code null} elements
+     * whenever the backing queue does.
+     *
+     * @param <E> the class of the objects in the queue
+     * @param queue the queue for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code queue} is permitted to hold
+     * @return a dynamically typesafe view of the specified queue
+     * @since 1.8
+     */
+    public static <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> type) {
+        return new CheckedQueue<>(queue, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedQueue<E>
+        extends CheckedCollection<E>
+        implements Queue<E>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 1433151992604707767L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Queue<E> queue;
+
+        CheckedQueue(Queue<E> queue, Class<E> elementType) {
+            super(queue, elementType);
+            this.queue = queue;
+        }
+
+        public E element()              {return queue.element();}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+        public E peek()                 {return queue.peek();}
+        public E poll()                 {return queue.poll();}
+        public E remove()               {return queue.remove();}
+        public boolean offer(E e)       {return queue.offer(typeCheck(e));}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified set.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a set contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the set
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * set cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned set permits insertion of null elements whenever
+     * the backing set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified set
+     * @since 1.5
+     */
+    public static <E> Set<E> checkedSet(Set<E> s, Class<E> type) {
+        return new CheckedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSet<E> extends CheckedCollection<E>
+                                 implements Set<E>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 4694047833775013803L;
+
+        CheckedSet(Set<E> s, Class<E> elementType) { super(s, elementType); }
+
+        public boolean equals(Object o) { return o == this || c.equals(o); }
+        public int hashCode()           { return c.hashCode(); }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a sorted set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the sorted set takes place through the view, it is
+     * <i>guaranteed</i> that the sorted set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned sorted set will be serializable if the specified sorted
+     * set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned sorted set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the sorted set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified sorted set
+     * @since 1.5
+     */
+    public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedSortedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedSet<E> extends CheckedSet<E>
+        implements SortedSet<E>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 1599911165492914959L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedSet<E> ss;
+
+        CheckedSortedSet(SortedSet<E> s, Class<E> type) {
+            super(s, type);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() { return ss.comparator(); }
+        public E first()                   { return ss.first(); }
+        public E last()                    { return ss.last(); }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return checkedSortedSet(ss.subSet(fromElement,toElement), type);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return checkedSortedSet(ss.headSet(toElement), type);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return checkedSortedSet(ss.tailSet(fromElement), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified navigable set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a navigable set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the navigable set takes place through the view, it is
+     * <em>guaranteed</em> that the navigable set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned navigable set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the navigable set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified navigable set
+     * @since 1.8
+     */
+    public static <E> NavigableSet<E> checkedNavigableSet(NavigableSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedNavigableSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableSet<E> extends CheckedSortedSet<E>
+        implements NavigableSet<E>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -5429120189805438922L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableSet<E> ns;
+
+        CheckedNavigableSet(NavigableSet<E> s, Class<E> type) {
+            super(s, type);
+            ns = s;
+        }
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()                         { return ns.pollFirst(); }
+        public E pollLast()                            {return ns.pollLast(); }
+        public NavigableSet<E> descendingSet()
+                      { return checkedNavigableSet(ns.descendingSet(), type); }
+        public Iterator<E> descendingIterator()
+            {return checkedNavigableSet(ns.descendingSet(), type).iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            return checkedNavigableSet(ns.subSet(fromElement, true, toElement, false), type);
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            return checkedNavigableSet(ns.headSet(toElement, false), type);
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            return checkedNavigableSet(ns.tailSet(fromElement, true), type);
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type);
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return checkedNavigableSet(ns.headSet(toElement, inclusive), type);
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return checkedNavigableSet(ns.tailSet(fromElement, inclusive), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified list.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a list contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the list
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * list cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned list will be serializable if the specified list
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned list permits insertion of null elements whenever
+     * the backing list does.
+     *
+     * @param <E> the class of the objects in the list
+     * @param list the list for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code list} is permitted to hold
+     * @return a dynamically typesafe view of the specified list
+     * @since 1.5
+     */
+    public static <E> List<E> checkedList(List<E> list, Class<E> type) {
+        return (list instanceof RandomAccess ?
+                new CheckedRandomAccessList<>(list, type) :
+                new CheckedList<>(list, type));
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedList<E>
+        extends CheckedCollection<E>
+        implements List<E>
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 65247728283967356L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final List<E> list;
+
+        CheckedList(List<E> list, Class<E> type) {
+            super(list, type);
+            this.list = list;
+        }
+
+        public boolean equals(Object o)  { return o == this || list.equals(o); }
+        public int hashCode()            { return list.hashCode(); }
+        public E get(int index)          { return list.get(index); }
+        public E remove(int index)       { return list.remove(index); }
+        public int indexOf(Object o)     { return list.indexOf(o); }
+        public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
+
+        public E set(int index, E element) {
+            return list.set(index, typeCheck(element));
+        }
+
+        public void add(int index, E element) {
+            list.add(index, typeCheck(element));
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            return list.addAll(index, checkedCopyOf(c));
+        }
+        public ListIterator<E> listIterator()   { return listIterator(0); }
+
+        public ListIterator<E> listIterator(final int index) {
+            final ListIterator<E> i = list.listIterator(index);
+
+            return new ListIterator<>() {
+                public boolean hasNext()     { return i.hasNext(); }
+                public E next()              { return i.next(); }
+                public boolean hasPrevious() { return i.hasPrevious(); }
+                public E previous()          { return i.previous(); }
+                public int nextIndex()       { return i.nextIndex(); }
+                public int previousIndex()   { return i.previousIndex(); }
+                public void remove()         {        i.remove(); }
+
+                public void set(E e) {
+                    i.set(typeCheck(e));
+                }
+
+                public void add(E e) {
+                    i.add(typeCheck(e));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedList<>(list.subList(fromIndex, toIndex), type);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @throws ClassCastException if the class of an element returned by the
+         *         operator prevents it from being added to this collection. The
+         *         exception may be thrown after some elements of the list have
+         *         already been replaced.
+         */
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            list.replaceAll(e -> typeCheck(operator.apply(e)));
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            list.sort(c);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedRandomAccessList<E> extends CheckedList<E>
+                                            implements RandomAccess
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 1638200125423088369L;
+
+        CheckedRandomAccessList(List<E> list, Class<E> type) {
+            super(list, type);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K, V> Map<K, V> checkedMap(Map<K, V> m,
+                                              Class<K> keyType,
+                                              Class<V> valueType) {
+        return new CheckedMap<>(m, keyType, valueType);
+    }
+
+
+    /**
+     * @serial include
+     */
+    private static class CheckedMap<K,V>
+        implements Map<K,V>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 5742860141034234728L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final Map<K, V> m;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Class<K> keyType;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Class<V> valueType;
+
+        private void typeCheck(Object key, Object value) {
+            if (key != null && !keyType.isInstance(key))
+                throw new ClassCastException(badKeyMsg(key));
+
+            if (value != null && !valueType.isInstance(value))
+                throw new ClassCastException(badValueMsg(value));
+        }
+
+        private BiFunction<? super K, ? super V, ? extends V> typeCheck(
+                BiFunction<? super K, ? super V, ? extends V> func) {
+            Objects.requireNonNull(func);
+            return (k, v) -> {
+                V newValue = func.apply(k, v);
+                typeCheck(k, newValue);
+                return newValue;
+            };
+        }
+
+        private String badKeyMsg(Object key) {
+            return "Attempt to insert " + key.getClass() +
+                    " key into map with key type " + keyType;
+        }
+
+        private String badValueMsg(Object value) {
+            return "Attempt to insert " + value.getClass() +
+                    " value into map with value type " + valueType;
+        }
+
+        CheckedMap(Map<K, V> m, Class<K> keyType, Class<V> valueType) {
+            this.m = Objects.requireNonNull(m);
+            this.keyType = Objects.requireNonNull(keyType);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        public int size()                      { return m.size(); }
+        public boolean isEmpty()               { return m.isEmpty(); }
+        public boolean containsKey(Object key) { return m.containsKey(key); }
+        public boolean containsValue(Object v) { return m.containsValue(v); }
+        public V get(Object key)               { return m.get(key); }
+        public V remove(Object key)            { return m.remove(key); }
+        public void clear()                    { m.clear(); }
+        public Set<K> keySet()                 { return m.keySet(); }
+        public Collection<V> values()          { return m.values(); }
+        public boolean equals(Object o)        { return o == this || m.equals(o); }
+        public int hashCode()                  { return m.hashCode(); }
+        public String toString()               { return m.toString(); }
+
+        public V put(K key, V value) {
+            typeCheck(key, value);
+            return m.put(key, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void putAll(Map<? extends K, ? extends V> t) {
+            // Satisfy the following goals:
+            // - good diagnostics in case of type mismatch
+            // - all-or-nothing semantics
+            // - protection from malicious t
+            // - correct behavior if t is a concurrent map
+            Object[] entries = t.entrySet().toArray();
+            List<Map.Entry<K,V>> checked = new ArrayList<>(entries.length);
+            for (Object o : entries) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object k = e.getKey();
+                Object v = e.getValue();
+                typeCheck(k, v);
+                checked.add(
+                        new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v));
+            }
+            for (Map.Entry<K,V> e : checked)
+                m.put(e.getKey(), e.getValue());
+        }
+
+        private transient Set<Map.Entry<K,V>> entrySet;
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new CheckedEntrySet<>(m.entrySet(), valueType);
+            return entrySet;
+        }
+
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            m.replaceAll(typeCheck(function));
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            typeCheck(key, value);
+            return m.putIfAbsent(key, value);
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            return m.remove(key, value);
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            typeCheck(key, newValue);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            typeCheck(key, value);
+            return m.replace(key, value);
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            Objects.requireNonNull(mappingFunction);
+            return m.computeIfAbsent(key, k -> {
+                V value = mappingFunction.apply(k);
+                typeCheck(k, value);
+                return value;
+            });
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.computeIfPresent(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.compute(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            Objects.requireNonNull(remappingFunction);
+            return m.merge(key, value, (v1, v2) -> {
+                V newValue = remappingFunction.apply(v1, v2);
+                typeCheck(null, newValue);
+                return newValue;
+            });
+        }
+
+        /**
+         * We need this class in addition to CheckedSet as Map.Entry permits
+         * modification of the backing Map via the setValue operation.  This
+         * class is subtle: there are many possible attacks that must be
+         * thwarted.
+         *
+         * @serial exclude
+         */
+        static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> {
+            private final Set<Map.Entry<K,V>> s;
+            private final Class<V> valueType;
+
+            CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) {
+                this.s = s;
+                this.valueType = valueType;
+            }
+
+            public int size()        { return s.size(); }
+            public boolean isEmpty() { return s.isEmpty(); }
+            public String toString() { return s.toString(); }
+            public int hashCode()    { return s.hashCode(); }
+            public void clear()      {        s.clear(); }
+
+            public boolean add(Map.Entry<K, V> e) {
+                throw new UnsupportedOperationException();
+            }
+            public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
+                throw new UnsupportedOperationException();
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                final Iterator<Map.Entry<K, V>> i = s.iterator();
+
+                return new Iterator<>() {
+                    public boolean hasNext() { return i.hasNext(); }
+                    public void remove()     { i.remove(); }
+
+                    public Map.Entry<K,V> next() {
+                        return checkedEntry(i.next(), valueType);
+                    }
+                    public void forEachRemaining(Consumer<? super Entry<K, V>> action) {
+                        Objects.requireNonNull(action);
+                        i.forEachRemaining(
+                            e -> action.accept(checkedEntry(e, valueType)));
+                    }
+                };
+            }
+
+            // Android-changed: Ignore IsInstanceOfClass warning. b/73288967, b/73344263.
+            // @SuppressWarnings("unchecked")
+            @SuppressWarnings({ "unchecked", "IsInstanceOfClass" })
+            public Object[] toArray() {
+                Object[] source = s.toArray();
+
+                /*
+                 * Ensure that we don't get an ArrayStoreException even if
+                 * s.toArray returns an array of something other than Object
+                 */
+                Object[] dest = (source.getClass() == Object[].class)
+                    ? source
+                    : new Object[source.length];
+
+                for (int i = 0; i < source.length; i++)
+                    dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
+                                           valueType);
+                return dest;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to s.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from s.
+                T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i],
+                                              valueType);
+                if (arr.length > a.length)
+                    return arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                // Android-changed: (b/247094511) instanceof pattern variable is not yet supported.
+                /*
+                return o instanceof Map.Entry<?, ?> e
+                        && s.contains((e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
+                 */
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                return s.contains(
+                        (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
+            }
+
+            /**
+             * The bulk collection methods are overridden to protect
+             * against an unscrupulous collection whose contains(Object o)
+             * method senses when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> c) {
+                for (Object o : c)
+                    if (!contains(o)) // Invokes safe contains() above
+                        return false;
+                return true;
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return s.remove(new AbstractMap.SimpleImmutableEntry
+                                <>((Map.Entry<?,?>)o));
+            }
+
+            public boolean removeAll(Collection<?> c) {
+                return batchRemove(c, false);
+            }
+            public boolean retainAll(Collection<?> c) {
+                return batchRemove(c, true);
+            }
+            private boolean batchRemove(Collection<?> c, boolean complement) {
+                Objects.requireNonNull(c);
+                boolean modified = false;
+                Iterator<Map.Entry<K,V>> it = iterator();
+                while (it.hasNext()) {
+                    if (c.contains(it.next()) != complement) {
+                        it.remove();
+                        modified = true;
+                    }
+                }
+                return modified;
+            }
+
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+                // Android-changed: (b/247094511) instanceof pattern variable is not yet supported
+                /*
+                return o instanceof Set<?> that
+                        && that.size() == s.size()
+                        && containsAll(that); // Invokes safe containsAll() above
+                 */
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> that = (Set<?>) o;
+                return that.size() == s.size()
+                        && containsAll(that); // Invokes safe containsAll() above
+            }
+
+            static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e,
+                                                            Class<T> valueType) {
+                return new CheckedEntry<>(e, valueType);
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map.Entry when asked to perform an equality check.
+             */
+            private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> {
+                private final Map.Entry<K, V> e;
+                private final Class<T> valueType;
+
+                CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) {
+                    this.e = Objects.requireNonNull(e);
+                    this.valueType = Objects.requireNonNull(valueType);
+                }
+
+                public K getKey()        { return e.getKey(); }
+                public V getValue()      { return e.getValue(); }
+                public int hashCode()    { return e.hashCode(); }
+                public String toString() { return e.toString(); }
+
+                public V setValue(V value) {
+                    if (value != null && !valueType.isInstance(value))
+                        throw new ClassCastException(badValueMsg(value));
+                    return e.setValue(value);
+                }
+
+                private String badValueMsg(Object value) {
+                    return "Attempt to insert " + value.getClass() +
+                        " value into map with value type " + valueType;
+                }
+
+                public boolean equals(Object o) {
+                    if (o == this)
+                        return true;
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    return e.equals(new AbstractMap.SimpleImmutableEntry
+                                    <>((Map.Entry<?,?>)o));
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedSortedMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedMap<K,V> extends CheckedMap<K,V>
+        implements SortedMap<K,V>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 1599671320688067438L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final SortedMap<K, V> sm;
+
+        CheckedSortedMap(SortedMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() { return sm.comparator(); }
+        public K firstKey()                       { return sm.firstKey(); }
+        public K lastKey()                        { return sm.lastKey(); }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedSortedMap(sm.subMap(fromKey, toKey),
+                                    keyType, valueType);
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            return checkedSortedMap(sm.headMap(toKey), keyType, valueType);
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified navigable map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <em>guaranteed</em> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> type of map keys
+     * @param <V> type of map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> checkedNavigableMap(NavigableMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedNavigableMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableMap<K,V> extends CheckedSortedMap<K,V>
+        implements NavigableMap<K,V>, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = -4852462692372534096L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final NavigableMap<K, V> nm;
+
+        CheckedNavigableMap(NavigableMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            nm = m;
+        }
+
+        public Comparator<? super K> comparator()   { return nm.comparator(); }
+        public K firstKey()                           { return nm.firstKey(); }
+        public K lastKey()                             { return nm.lastKey(); }
+
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = nm.lowerEntry(key);
+            return (null != lower)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(lower, valueType)
+                : null;
+        }
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = nm.floorEntry(key);
+            return (null != floor)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(floor, valueType)
+                : null;
+        }
+
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(ceiling, valueType)
+                : null;
+        }
+
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = nm.higherEntry(key);
+            return (null != higher)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(higher, valueType)
+                : null;
+        }
+
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = nm.firstEntry();
+            return (null != first)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(first, valueType)
+                : null;
+        }
+
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = nm.lastEntry();
+            return (null != last)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(last, valueType)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry() {
+            Entry<K,V> entry = nm.pollFirstEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public Entry<K, V> pollLastEntry() {
+            Entry<K,V> entry = nm.pollLastEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public NavigableMap<K, V> descendingMap() {
+            return checkedNavigableMap(nm.descendingMap(), keyType, valueType);
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            return checkedNavigableSet(nm.navigableKeySet(), keyType);
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return checkedNavigableSet(nm.descendingKeySet(), keyType);
+        }
+
+        @Override
+        public NavigableMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedNavigableMap(nm.subMap(fromKey, true, toKey, false),
+                                    keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> headMap(K toKey) {
+            return checkedNavigableMap(nm.headMap(toKey, false), keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> tailMap(K fromKey) {
+            return checkedNavigableMap(nm.tailMap(fromKey, true), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType);
+        }
+    }
+
+    // Empty collections
+
+    /**
+     * Returns an iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} always returns {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} always throws {@link
+     * NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} always throws {@link
+     * IllegalStateException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> emptyIterator() {
+        return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyIterator<E> implements Iterator<E> {
+        static final EmptyIterator<Object> EMPTY_ITERATOR
+            = new EmptyIterator<>();
+
+        public boolean hasNext() { return false; }
+        public E next() { throw new NoSuchElementException(); }
+        public void remove() { throw new IllegalStateException(); }
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+    }
+
+    /**
+     * Returns a list iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} and {@link
+     * ListIterator#hasPrevious hasPrevious} always return {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} and {@link ListIterator#previous
+     * previous} always throw {@link NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} and {@link ListIterator#set
+     * set} always throw {@link IllegalStateException}.</li>
+     * <li>{@link ListIterator#add add} always throws {@link
+     * UnsupportedOperationException}.</li>
+     * <li>{@link ListIterator#nextIndex nextIndex} always returns
+     * {@code 0}.</li>
+     * <li>{@link ListIterator#previousIndex previousIndex} always
+     * returns {@code -1}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty list iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> ListIterator<T> emptyListIterator() {
+        return (ListIterator<T>) EmptyListIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyListIterator<E>
+        extends EmptyIterator<E>
+        implements ListIterator<E>
+    {
+        static final EmptyListIterator<Object> EMPTY_ITERATOR
+            = new EmptyListIterator<>();
+
+        public boolean hasPrevious() { return false; }
+        public E previous() { throw new NoSuchElementException(); }
+        public int nextIndex()     { return 0; }
+        public int previousIndex() { return -1; }
+        public void set(E e) { throw new IllegalStateException(); }
+        public void add(E e) { throw new UnsupportedOperationException(); }
+    }
+
+    /**
+     * Returns an enumeration that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Enumeration#hasMoreElements hasMoreElements} always
+     * returns {@code false}.</li>
+     * <li> {@link Enumeration#nextElement nextElement} always throws
+     * {@link NoSuchElementException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param  <T> the class of the objects in the enumeration
+     * @return an empty enumeration
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Enumeration<T> emptyEnumeration() {
+        return (Enumeration<T>) EmptyEnumeration.EMPTY_ENUMERATION;
+    }
+
+    private static class EmptyEnumeration<E> implements Enumeration<E> {
+        static final EmptyEnumeration<Object> EMPTY_ENUMERATION
+            = new EmptyEnumeration<>();
+
+        public boolean hasMoreElements() { return false; }
+        public E nextElement() { throw new NoSuchElementException(); }
+        public Iterator<E> asIterator() { return emptyIterator(); }
+    }
+
+    /**
+     * The empty set (immutable).  This set is serializable.
+     *
+     * @see #emptySet()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Set EMPTY_SET = new EmptySet<>();
+
+    /**
+     * Returns an empty set (immutable).  This set is serializable.
+     * Unlike the like-named field, this method is parameterized.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty set:
+     * <pre>
+     *     Set&lt;String&gt; s = Collections.emptySet();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Set} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param  <T> the class of the objects in the set
+     * @return the empty set
+     *
+     * @see #EMPTY_SET
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> Set<T> emptySet() {
+        return (Set<T>) EMPTY_SET;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptySet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 1582296315990362920L;
+
+        public Iterator<E> iterator() { return emptyIterator(); }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+        public void clear() {}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        @java.io.Serial
+        private Object readResolve() {
+            return EMPTY_SET;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns an empty sorted set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * sorted set:
+     * <pre> {@code
+     *     SortedSet<String> s = Collections.emptySortedSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty sorted set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> SortedSet<E> emptySortedSet() {
+        return (SortedSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * Returns an empty navigable set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * navigable set:
+     * <pre> {@code
+     *     NavigableSet<String> s = Collections.emptyNavigableSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not
+     * create a separate {@code NavigableSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty navigable set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> NavigableSet<E> emptyNavigableSet() {
+        return (NavigableSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * The empty list (immutable).  This list is serializable.
+     *
+     * @see #emptyList()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final List EMPTY_LIST = new EmptyList<>();
+
+    /**
+     * Returns an empty list (immutable).  This list is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty list:
+     * <pre>
+     *     List&lt;String&gt; s = Collections.emptyList();
+     * </pre>
+     *
+     * @implNote
+     * Implementations of this method need not create a separate {@code List}
+     * object for each call.   Using this method is likely to have comparable
+     * cost to using the like-named field.  (Unlike this method, the field does
+     * not provide type safety.)
+     *
+     * @param <T> type of elements, if there were any, in the list
+     * @return an empty immutable list
+     *
+     * @see #EMPTY_LIST
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> List<T> emptyList() {
+        return (List<T>) EMPTY_LIST;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 8842843931221139166L;
+
+        public Iterator<E> iterator() {
+            return emptyIterator();
+        }
+        public ListIterator<E> listIterator() {
+            return emptyListIterator();
+        }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+        public void clear() {}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        public E get(int index) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+
+        public boolean equals(Object o) {
+            return (o instanceof List) && ((List<?>)o).isEmpty();
+        }
+
+        public int hashCode() { return 1; }
+
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        @java.io.Serial
+        private Object readResolve() {
+            return EMPTY_LIST;
+        }
+    }
+
+    /**
+     * The empty map (immutable).  This map is serializable.
+     *
+     * @see #emptyMap()
+     * @since 1.3
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Map EMPTY_MAP = new EmptyMap<>();
+
+    /**
+     * Returns an empty map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre>
+     *     Map&lt;String, Date&gt; s = Collections.emptyMap();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Map} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty map
+     * @see #EMPTY_MAP
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> Map<K,V> emptyMap() {
+        return (Map<K,V>) EMPTY_MAP;
+    }
+
+    /**
+     * Returns an empty sorted map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     SortedMap<String, Date> s = Collections.emptySortedMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty sorted map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> SortedMap<K,V> emptySortedMap() {
+        return (SortedMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * Returns an empty navigable map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     NavigableMap<String, Date> s = Collections.emptyNavigableMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code NavigableMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty navigable map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> NavigableMap<K,V> emptyNavigableMap() {
+        return (NavigableMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyMap<K,V>
+        extends AbstractMap<K,V>
+        implements Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 6428348081105594320L;
+
+        public int size()                          {return 0;}
+        public boolean isEmpty()                   {return true;}
+        public void clear()                        {}
+        public boolean containsKey(Object key)     {return false;}
+        public boolean containsValue(Object value) {return false;}
+        public V get(Object key)                   {return null;}
+        public Set<K> keySet()                     {return emptySet();}
+        public Collection<V> values()              {return emptySet();}
+        public Set<Map.Entry<K,V>> entrySet()      {return emptySet();}
+
+        public boolean equals(Object o) {
+            return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
+        }
+
+        public int hashCode()                      {return 0;}
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object k, V defaultValue) {
+            return defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            Objects.requireNonNull(function);
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Preserves singleton property
+        @java.io.Serial
+        private Object readResolve() {
+            return EMPTY_MAP;
+        }
+    }
+
+    // Singleton collections
+
+    /**
+     * Returns an immutable set containing only the specified object.
+     * The returned set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param o the sole object to be stored in the returned set.
+     * @return an immutable set containing only the specified object.
+     */
+    public static <T> Set<T> singleton(T o) {
+        return new SingletonSet<>(o);
+    }
+
+    static <E> Iterator<E> singletonIterator(final E e) {
+        return new Iterator<>() {
+            private boolean hasNext = true;
+            public boolean hasNext() {
+                return hasNext;
+            }
+            public E next() {
+                if (hasNext) {
+                    hasNext = false;
+                    return e;
+                }
+                throw new NoSuchElementException();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void forEachRemaining(Consumer<? super E> action) {
+                Objects.requireNonNull(action);
+                if (hasNext) {
+                    hasNext = false;
+                    action.accept(e);
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates a {@code Spliterator} with only the specified element
+     *
+     * @param <T> Type of elements
+     * @return A singleton {@code Spliterator}
+     */
+    static <T> Spliterator<T> singletonSpliterator(final T element) {
+        return new Spliterator<>() {
+            long est = 1;
+
+            @Override
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                Objects.requireNonNull(consumer);
+                if (est > 0) {
+                    est--;
+                    consumer.accept(element);
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                tryAdvance(consumer);
+            }
+
+            @Override
+            public long estimateSize() {
+                return est;
+            }
+
+            @Override
+            public int characteristics() {
+                int value = (element != null) ? Spliterator.NONNULL : 0;
+
+                return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE |
+                       Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        };
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonSet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 3193687207550431679L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final E element;
+
+        SingletonSet(E e) {element = e;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size() {return 1;}
+
+        public boolean contains(Object o) {return eq(o, element);}
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(element);
+        }
+    }
+
+    /**
+     * Returns an immutable list containing only the specified object.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param o the sole object to be stored in the returned list.
+     * @return an immutable list containing only the specified object.
+     * @since 1.3
+     */
+    public static <T> List<T> singletonList(T o) {
+        return new SingletonList<>(o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+
+        @java.io.Serial
+        private static final long serialVersionUID = 3093736618740652951L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final E element;
+
+        SingletonList(E obj)                {element = obj;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size()                   {return 1;}
+
+        public boolean contains(Object obj) {return eq(obj, element);}
+
+        public E get(int index) {
+            if (index != 0)
+              throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
+            return element;
+        }
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+        @Override
+        public int hashCode() {
+            return 31 + Objects.hashCode(element);
+        }
+    }
+
+    /**
+     * Returns an immutable map, mapping only the specified key to the
+     * specified value.  The returned map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param key the sole key to be stored in the returned map.
+     * @param value the value to which the returned map maps {@code key}.
+     * @return an immutable map containing only the specified key-value
+     *         mapping.
+     * @since 1.3
+     */
+    public static <K,V> Map<K,V> singletonMap(K key, V value) {
+        return new SingletonMap<>(key, value);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonMap<K,V>
+          extends AbstractMap<K,V>
+          implements Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -6979724477215052911L;
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final K k;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final V v;
+
+        SingletonMap(K key, V value) {
+            k = key;
+            v = value;
+        }
+
+        public int size()                                           {return 1;}
+        public boolean isEmpty()                                {return false;}
+        public boolean containsKey(Object key)             {return eq(key, k);}
+        public boolean containsValue(Object value)       {return eq(value, v);}
+        public V get(Object key)              {return (eq(key, k) ? v : null);}
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = singleton(k);
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = Collections.singleton(
+                    new SimpleImmutableEntry<>(k, v));
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = singleton(v);
+            return values;
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object key, V defaultValue) {
+            return eq(key, k) ? v : defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            action.accept(k, v);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
+        }
+    }
+
+    // Miscellaneous
+
+    /**
+     * Returns an immutable list consisting of {@code n} copies of the
+     * specified object.  The newly allocated data object is tiny (it contains
+     * a single reference to the data object).  This method is useful in
+     * combination with the {@code List.addAll} method to grow lists.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the object to copy and of the objects
+     *         in the returned list.
+     * @param  n the number of elements in the returned list.
+     * @param  o the element to appear repeatedly in the returned list.
+     * @return an immutable list consisting of {@code n} copies of the
+     *         specified object.
+     * @throws IllegalArgumentException if {@code n < 0}
+     * @see    List#addAll(Collection)
+     * @see    List#addAll(int, Collection)
+     */
+    public static <T> List<T> nCopies(int n, T o) {
+        if (n < 0)
+            throw new IllegalArgumentException("List length = " + n);
+        return new CopiesList<>(n, o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class CopiesList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 2739099268398711800L;
+
+        final int n;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final E element;
+
+        CopiesList(int n, E e) {
+            assert n >= 0;
+            this.n = n;
+            element = e;
+        }
+
+        public int size() {
+            return n;
+        }
+
+        public boolean contains(Object obj) {
+            return n != 0 && eq(obj, element);
+        }
+
+        public int indexOf(Object o) {
+            return contains(o) ? 0 : -1;
+        }
+
+        public int lastIndexOf(Object o) {
+            return contains(o) ? n - 1 : -1;
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, n);
+            return element;
+        }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int n = this.n;
+            E element = this.element;
+            for (int i = 0; i < n; i++) {
+                action.accept(element);
+            }
+        }
+
+        public Object[] toArray() {
+            final Object[] a = new Object[n];
+            if (element != null)
+                Arrays.fill(a, 0, n, element);
+            return a;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final int n = this.n;
+            if (a.length < n) {
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), n);
+                if (element != null)
+                    Arrays.fill(a, 0, n, element);
+            } else {
+                Arrays.fill(a, 0, n, element);
+                if (a.length > n)
+                    a[n] = null;
+            }
+            return a;
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            if (fromIndex < 0)
+                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+            if (toIndex > n)
+                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+            if (fromIndex > toIndex)
+                throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                                   ") > toIndex(" + toIndex + ")");
+            return new CopiesList<>(toIndex - fromIndex, element);
+        }
+
+        @Override
+        public int hashCode() {
+            if (n == 0) return 1;
+            // hashCode of n repeating elements is 31^n + elementHash * Sum(31^k, k = 0..n-1)
+            // this implementation completes in O(log(n)) steps taking advantage of
+            // 31^(2*n) = (31^n)^2 and Sum(31^k, k = 0..(2*n-1)) = Sum(31^k, k = 0..n-1) * (31^n + 1)
+            int pow = 31;
+            int sum = 1;
+            for (int i = Integer.numberOfLeadingZeros(n) + 1; i < Integer.SIZE; i++) {
+                sum *= pow + 1;
+                pow *= pow;
+                if ((n << i) < 0) {
+                    pow *= 31;
+                    sum = sum * 31 + 1;
+                }
+            }
+            return pow + sum * (element == null ? 0 : element.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            // Android-changed: (b/247094511) instanceof pattern variable is not yet supported.
+            // if (o instanceof CopiesList<?> other) {
+            if (o instanceof CopiesList<?>) {
+                CopiesList<?> other = (CopiesList<?>) o;
+                return n == other.n && (n == 0 || eq(element, other.element));
+            }
+            if (!(o instanceof List))
+                return false;
+
+            int remaining = n;
+            E e = element;
+            Iterator<?> itr = ((List<?>) o).iterator();
+            if (e == null) {
+                while (itr.hasNext() && remaining-- > 0) {
+                    if (itr.next() != null)
+                        return false;
+                }
+            } else {
+                while (itr.hasNext() && remaining-- > 0) {
+                    if (!e.equals(itr.next()))
+                        return false;
+                }
+            }
+            return remaining == 0 && !itr.hasNext();
+        }
+
+        // Override default methods in Collection
+        @Override
+        public Stream<E> stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream<E> parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return stream().spliterator();
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+            ois.defaultReadObject();
+            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, n);
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em> on a collection of objects that implement the
+     * {@code Comparable} interface.  (The natural ordering is the ordering
+     * imposed by the objects' own {@code compareTo} method.)  This enables a
+     * simple idiom for sorting (or maintaining) collections (or arrays) of
+     * objects that implement the {@code Comparable} interface in
+     * reverse-natural-order.  For example, suppose {@code a} is an array of
+     * strings. Then: <pre>
+     *          Arrays.sort(a, Collections.reverseOrder());
+     * </pre> sorts the array in reverse-lexicographic (alphabetical) order.<p>
+     *
+     * The returned comparator is serializable.
+     *
+     * @apiNote
+     * This method returns a {@code Comparator} that is suitable for sorting
+     * elements in reverse order. To obtain a reverse-ordered <i>view</i> of a
+     * sequenced collection, use the {@link SequencedCollection#reversed
+     * SequencedCollection.reversed} method. Or, to obtain a reverse-ordered
+     * <i>view</i> of a sequenced map, use the {@link SequencedMap#reversed
+     * SequencedMap.reversed} method.
+     *
+     * @param  <T> the class of the objects compared by the comparator
+     * @return A comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on a collection of objects that implement
+     *         the {@code Comparable} interface.
+     * @see Comparable
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Comparator<T> reverseOrder() {
+        return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator
+        implements Comparator<Comparable<Object>>, Serializable {
+
+        @java.io.Serial
+        private static final long serialVersionUID = 7207038068494060240L;
+
+        static final ReverseComparator REVERSE_ORDER
+            = new ReverseComparator();
+
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c2.compareTo(c1);
+        }
+
+        @java.io.Serial
+        private Object readResolve() { return Collections.reverseOrder(); }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.naturalOrder();
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of the specified
+     * comparator.  If the specified comparator is {@code null}, this method is
+     * equivalent to {@link #reverseOrder()} (in other words, it returns a
+     * comparator that imposes the reverse of the <em>natural ordering</em> on
+     * a collection of objects that implement the Comparable interface).
+     *
+     * <p>The returned comparator is serializable (assuming the specified
+     * comparator is also serializable or {@code null}).
+     *
+     * @apiNote
+     * This method returns a {@code Comparator} that is suitable for sorting
+     * elements in reverse order. To obtain a reverse-ordered <i>view</i> of a
+     * sequenced collection, use the {@link SequencedCollection#reversed
+     * SequencedCollection.reversed} method. Or, to obtain a reverse-ordered
+     * <i>view</i> of a sequenced map, use the {@link SequencedMap#reversed
+     * SequencedMap.reversed} method.
+     *
+     * @param <T> the class of the objects compared by the comparator
+     * @param cmp a comparator who's ordering is to be reversed by the returned
+     * comparator or {@code null}
+     * @return A comparator that imposes the reverse ordering of the
+     *         specified comparator.
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
+        if (cmp == null) {
+            return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
+        } else if (cmp == ReverseComparator.REVERSE_ORDER) {
+            return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
+        } else if (cmp == Comparators.NaturalOrderComparator.INSTANCE) {
+            return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
+        } else if (cmp instanceof ReverseComparator2) {
+            return ((ReverseComparator2<T>) cmp).cmp;
+        } else {
+            return new ReverseComparator2<>(cmp);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator2<T> implements Comparator<T>,
+        Serializable
+    {
+        @java.io.Serial
+        private static final long serialVersionUID = 4374092139857L;
+
+        /**
+         * The comparator specified in the static factory.  This will never
+         * be null, as the static factory returns a ReverseComparator
+         * instance if its argument is null.
+         *
+         * @serial
+         */
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Comparator<T> cmp;
+
+        ReverseComparator2(Comparator<T> cmp) {
+            assert cmp != null;
+            this.cmp = cmp;
+        }
+
+        public int compare(T t1, T t2) {
+            return cmp.compare(t2, t1);
+        }
+
+        public boolean equals(Object o) {
+            return (o == this) ||
+                (o instanceof ReverseComparator2<?> that &&
+                 cmp.equals(that.cmp));
+        }
+
+        public int hashCode() {
+            return cmp.hashCode() ^ Integer.MIN_VALUE;
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return cmp;
+        }
+    }
+
+    /**
+     * Returns an enumeration over the specified collection.  This provides
+     * interoperability with legacy APIs that require an enumeration
+     * as input.
+     *
+     * <p>The iterator returned from a call to {@link Enumeration#asIterator()}
+     * does not support removal of elements from the specified collection.  This
+     * is necessary to avoid unintentionally increasing the capabilities of the
+     * returned enumeration.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param c the collection for which an enumeration is to be returned.
+     * @return an enumeration over the specified collection.
+     * @see Enumeration
+     */
+    public static <T> Enumeration<T> enumeration(final Collection<T> c) {
+        return new Enumeration<>() {
+            private final Iterator<T> i = c.iterator();
+
+            public boolean hasMoreElements() {
+                return i.hasNext();
+            }
+
+            public T nextElement() {
+                return i.next();
+            }
+        };
+    }
+
+    /**
+     * Returns an array list containing the elements returned by the
+     * specified enumeration in the order they are returned by the
+     * enumeration.  This method provides interoperability between
+     * legacy APIs that return enumerations and new APIs that require
+     * collections.
+     *
+     * @param <T> the class of the objects returned by the enumeration
+     * @param e enumeration providing elements for the returned
+     *          array list
+     * @return an array list containing the elements returned
+     *         by the specified enumeration.
+     * @since 1.4
+     * @see Enumeration
+     * @see ArrayList
+     */
+    public static <T> ArrayList<T> list(Enumeration<T> e) {
+        ArrayList<T> l = new ArrayList<>();
+        while (e.hasMoreElements())
+            l.add(e.nextElement());
+        return l;
+    }
+
+    /**
+     * Returns true if the specified arguments are equal, or both null.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    static boolean eq(Object o1, Object o2) {
+        return o1==null ? o2==null : o1.equals(o2);
+    }
+
+    /**
+     * Returns the number of elements in the specified collection equal to the
+     * specified object.  More formally, returns the number of elements
+     * {@code e} in the collection such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param c the collection in which to determine the frequency
+     *     of {@code o}
+     * @param o the object whose frequency is to be determined
+     * @return the number of elements in {@code c} equal to {@code o}
+     * @throws NullPointerException if {@code c} is null
+     * @since 1.5
+     */
+    public static int frequency(Collection<?> c, Object o) {
+        int result = 0;
+        if (o == null) {
+            for (Object e : c)
+                if (e == null)
+                    result++;
+        } else {
+            for (Object e : c)
+                if (o.equals(e))
+                    result++;
+        }
+        return result;
+    }
+
+    /**
+     * Returns {@code true} if the two specified collections have no
+     * elements in common.
+     *
+     * <p>Care must be exercised if this method is used on collections that
+     * do not comply with the general contract for {@code Collection}.
+     * Implementations may elect to iterate over either collection and test
+     * for containment in the other collection (or to perform any equivalent
+     * computation).  If either collection uses a nonstandard equality test
+     * (as does a {@link SortedSet} whose ordering is not <em>compatible with
+     * equals</em>, or the key set of an {@link IdentityHashMap}), both
+     * collections must use the same nonstandard equality test, or the
+     * result of this method is undefined.
+     *
+     * <p>Care must also be exercised when using collections that have
+     * restrictions on the elements that they may contain. Collection
+     * implementations are allowed to throw exceptions for any operation
+     * involving elements they deem ineligible. For absolute safety the
+     * specified collections should contain only elements which are
+     * eligible elements for both collections.
+     *
+     * <p>Note that it is permissible to pass the same collection in both
+     * parameters, in which case the method will return {@code true} if and
+     * only if the collection is empty.
+     *
+     * @param c1 a collection
+     * @param c2 a collection
+     * @return {@code true} if the two specified collections have no
+     * elements in common.
+     * @throws NullPointerException if either collection is {@code null}.
+     * @throws NullPointerException if one collection contains a {@code null}
+     * element and {@code null} is not an eligible element for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if one collection contains an element that is
+     * of a type which is ineligible for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.5
+     */
+    public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
+        // The collection to be used for contains(). Preference is given to
+        // the collection who's contains() has lower O() complexity.
+        Collection<?> contains = c2;
+        // The collection to be iterated. If the collections' contains() impl
+        // are of different O() complexity, the collection with slower
+        // contains() will be used for iteration. For collections who's
+        // contains() are of the same complexity then best performance is
+        // achieved by iterating the smaller collection.
+        Collection<?> iterate = c1;
+
+        // Performance optimization cases. The heuristics:
+        //   1. Generally iterate over c1.
+        //   2. If c1 is a Set then iterate over c2.
+        //   3. If either collection is empty then result is always true.
+        //   4. Iterate over the smaller Collection.
+        if (c1 instanceof Set) {
+            // Use c1 for contains as a Set's contains() is expected to perform
+            // better than O(N/2)
+            iterate = c2;
+            contains = c1;
+        } else if (!(c2 instanceof Set)) {
+            // Both are mere Collections. Iterate over smaller collection.
+            // Example: If c1 contains 3 elements and c2 contains 50 elements and
+            // assuming contains() requires ceiling(N/2) comparisons then
+            // checking for all c1 elements in c2 would require 75 comparisons
+            // (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring
+            // 100 comparisons (50 * ceiling(3/2)).
+            int c1size = c1.size();
+            int c2size = c2.size();
+            if (c1size == 0 || c2size == 0) {
+                // At least one collection is empty. Nothing will match.
+                return true;
+            }
+
+            if (c1size > c2size) {
+                iterate = c2;
+                contains = c1;
+            }
+        }
+
+        for (Object e : iterate) {
+            if (contains.contains(e)) {
+               // Found a common element. Collections are not disjoint.
+                return false;
+            }
+        }
+
+        // No common elements were found.
+        return true;
+    }
+
+    /**
+     * Adds all of the specified elements to the specified collection.
+     * Elements to be added may be specified individually or as an array.
+     * The behaviour of this convenience method is similar to that of
+     * {@code c.addAll(Collections.unmodifiableList(Arrays.asList(elements)))}.
+     *
+     * <p>When elements are specified individually, this method provides a
+     * convenient way to add a few elements to an existing collection:
+     * <pre>
+     *     Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
+     * </pre>
+     *
+     * @param  <T> the class of the elements to add and of the collection
+     * @param c the collection into which {@code elements} are to be inserted
+     * @param elements the elements to insert into {@code c}
+     * @return {@code true} if the collection changed as a result of the call
+     * @throws UnsupportedOperationException if {@code c} does not support
+     *         the {@code add} operation
+     * @throws NullPointerException if {@code elements} contains one or more
+     *         null values and {@code c} does not permit null elements, or
+     *         if {@code c} or {@code elements} are {@code null}
+     * @throws IllegalArgumentException if some property of a value in
+     *         {@code elements} prevents it from being added to {@code c}
+     * @see Collection#addAll(Collection)
+     * @since 1.5
+     */
+    @SafeVarargs
+    public static <T> boolean addAll(Collection<? super T> c, T... elements) {
+        boolean result = false;
+        for (T element : elements)
+            result |= c.add(element);
+        return result;
+    }
+
+    /**
+     * Returns a set backed by the specified map.  The resulting set displays
+     * the same ordering, concurrency, and performance characteristics as the
+     * backing map.  In essence, this factory method provides a {@link Set}
+     * implementation corresponding to any {@link Map} implementation.  There
+     * is no need to use this method on a {@link Map} implementation that
+     * already has a corresponding {@link Set} implementation (such as {@link
+     * HashMap} or {@link TreeMap}).
+     *
+     * <p>Each method invocation on the set returned by this method results in
+     * exactly one method invocation on the backing map or its {@code keySet}
+     * view, with one exception.  The {@code addAll} method is implemented
+     * as a sequence of {@code put} invocations on the backing map.
+     *
+     * <p>The specified map must be empty at the time this method is invoked,
+     * and should not be accessed directly after this method returns.  These
+     * conditions are ensured if the map is created empty, passed directly
+     * to this method, and no reference to the map is retained, as illustrated
+     * in the following code fragment:
+     * <pre>
+     *    Set&lt;Object&gt; weakHashSet = Collections.newSetFromMap(
+     *        new WeakHashMap&lt;Object, Boolean&gt;());
+     * </pre>
+     *
+     * @param <E> the class of the map keys and of the objects in the
+     *        returned set
+     * @param map the backing map
+     * @return the set backed by the map
+     * @throws IllegalArgumentException if {@code map} is not empty
+     * @since 1.6
+     */
+    public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
+        if (! map.isEmpty()) // implicit null check
+            throw new IllegalArgumentException("Map is non-empty");
+        return new SetFromMap<>(map);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SetFromMap<E> extends AbstractSet<E>
+        implements Set<E>, Serializable
+    {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Map<E, Boolean> m;          // The backing map
+        private transient Set<E> s;       // Its keySet
+
+        SetFromMap(Map<E, Boolean> map) {
+            m = map;
+            s = map.keySet();
+        }
+
+        public void clear()               {        m.clear(); }
+        public int size()                 { return m.size(); }
+        public boolean isEmpty()          { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o)   { return m.remove(o) != null; }
+        public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
+        public Iterator<E> iterator()     { return s.iterator(); }
+        public Object[] toArray()         { return s.toArray(); }
+        public <T> T[] toArray(T[] a)     { return s.toArray(a); }
+        public String toString()          { return s.toString(); }
+        public int hashCode()             { return s.hashCode(); }
+        public boolean equals(Object o)   { return o == this || s.equals(o); }
+        public boolean containsAll(Collection<?> c) {return s.containsAll(c);}
+        public boolean removeAll(Collection<?> c)   {return s.removeAll(c);}
+        public boolean retainAll(Collection<?> c)   {return s.retainAll(c);}
+        // addAll is the only inherited implementation
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            s.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return s.removeIf(filter);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {return s.spliterator();}
+        @Override
+        public Stream<E> stream()           {return s.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return s.parallelStream();}
+
+        @java.io.Serial
+        private static final long serialVersionUID = 2454657854757543876L;
+
+        @java.io.Serial
+        private void readObject(java.io.ObjectInputStream stream)
+            throws IOException, ClassNotFoundException
+        {
+            stream.defaultReadObject();
+            s = m.keySet();
+        }
+
+        @java.io.Serial
+        private void readObjectNoData() throws java.io.ObjectStreamException {
+            throw new java.io.InvalidObjectException("missing SetFromMap data");
+        }
+    }
+
+    /**
+     * Returns a sequenced set backed by the specified map.  The resulting set displays
+     * the same ordering, concurrency, and performance characteristics as the
+     * backing map. In essence, this factory method provides a {@link SequencedSet}
+     * implementation corresponding to any {@link SequencedMap} implementation.
+     *
+     * <p>Each method invocation on the set returned by this method results in
+     * exactly one method invocation on the backing map or its {@code keySet}
+     * view, with one exception.  The {@code addAll} method is implemented
+     * as a sequence of {@code put} invocations on the backing map.
+     *
+     * <p>The specified map must be empty at the time this method is invoked,
+     * and should not be accessed directly after this method returns.  These
+     * conditions are ensured if the map is created empty, passed directly
+     * to this method, and no reference to the map is retained.
+     *
+     * @apiNote
+     * The following example code creates a {@code SequencedSet} from a
+     * {@code LinkedHashMap}. This differs from a {@code LinkedHashSet}
+     * in that the map's {@code removeEldestEntry} is overridden to provide
+     * an eviction policy, which is not possible with a {@code LinkedHashSet}.
+     *
+     * {@snippet :
+     *     SequencedSet<String> set = Collections.newSequencedSetFromMap(
+     *         new LinkedHashMap<String, Boolean>() {
+     *             protected boolean removeEldestEntry(Map.Entry<String, Boolean> e) {
+     *                 return this.size() > 5;
+     *             }
+     *        });
+     * }
+     *
+     * @param <E> the class of the map keys and of the objects in the
+     *        returned set
+     * @param map the backing map
+     * @return the set backed by the map
+     * @throws IllegalArgumentException if {@code map} is not empty
+     * @since 21
+     */
+    public static <E> SequencedSet<E> newSequencedSetFromMap(SequencedMap<E, Boolean> map) {
+        if (! map.isEmpty()) // implicit null check
+            throw new IllegalArgumentException("Map is non-empty");
+        return new SequencedSetFromMap<>(map);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SequencedSetFromMap<E> extends SetFromMap<E> implements SequencedSet<E> {
+        private E nsee(Map.Entry<E, Boolean> e) {
+            if (e == null) {
+                throw new NoSuchElementException();
+            } else {
+                return e.getKey();
+            }
+        }
+
+        private SequencedMap<E, Boolean> map() {
+            return (SequencedMap<E, Boolean>) super.m;
+        }
+
+        SequencedSetFromMap(SequencedMap<E, Boolean> map) {
+            super(map);
+        }
+
+        // Even though this wrapper class is serializable, the reversed view is effectively
+        // not serializable because it points to the reversed map view, which usually isn't
+        // serializable.
+        public SequencedSet<E> reversed() { return new SequencedSetFromMap<>(map().reversed()); }
+
+        public void addFirst(E e) { map().putFirst(e, Boolean.TRUE); }
+        public void addLast(E e)  { map().putLast(e, Boolean.TRUE); }
+        public E getFirst()       { return nsee(map().firstEntry()); }
+        public E getLast()        { return nsee(map().lastEntry()); }
+        public E removeFirst()    { return nsee(map().pollFirstEntry()); }
+        public E removeLast()     { return nsee(map().pollLastEntry()); }
+
+        @java.io.Serial
+        private static final long serialVersionUID = -3943479744841433802L;
+    }
+
+    /**
+     * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo)
+     * {@link Queue}. Method {@code add} is mapped to {@code push},
+     * {@code remove} is mapped to {@code pop} and so on. This
+     * view can be useful when you would like to use a method
+     * requiring a {@code Queue} but you need Lifo ordering.
+     *
+     * <p>Each method invocation on the queue returned by this method
+     * results in exactly one method invocation on the backing deque, with
+     * one exception.  The {@link Queue#addAll addAll} method is
+     * implemented as a sequence of {@link Deque#addFirst addFirst}
+     * invocations on the backing deque.
+     *
+     * @apiNote
+     * This method provides a view that inverts the sense of certain operations,
+     * but it doesn't reverse the encounter order. To obtain a reverse-ordered
+     * view, use the {@link Deque#reversed Deque.reversed} method.
+     *
+     * @param  <T> the class of the objects in the deque
+     * @param deque the deque
+     * @return the queue
+     * @since  1.6
+     */
+    public static <T> Queue<T> asLifoQueue(Deque<T> deque) {
+        return new AsLIFOQueue<>(Objects.requireNonNull(deque));
+    }
+
+    /**
+     * @serial include
+     */
+    static class AsLIFOQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 1802017725587941708L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final Deque<E> q;
+        AsLIFOQueue(Deque<E> q)                     { this.q = q; }
+        public boolean add(E e)                     { q.addFirst(e); return true; }
+        public boolean offer(E e)                   { return q.offerFirst(e); }
+        public E poll()                             { return q.pollFirst(); }
+        public E remove()                           { return q.removeFirst(); }
+        public E peek()                             { return q.peekFirst(); }
+        public E element()                          { return q.getFirst(); }
+        public void clear()                         {        q.clear(); }
+        public int size()                           { return q.size(); }
+        public boolean isEmpty()                    { return q.isEmpty(); }
+        public boolean contains(Object o)           { return q.contains(o); }
+        public boolean remove(Object o)             { return q.remove(o); }
+        public Iterator<E> iterator()               { return q.iterator(); }
+        public Object[] toArray()                   { return q.toArray(); }
+        public <T> T[] toArray(T[] a)               { return q.toArray(a); }
+        public <T> T[] toArray(IntFunction<T[]> f)  { return q.toArray(f); }
+        public String toString()                    { return q.toString(); }
+        public boolean containsAll(Collection<?> c) { return q.containsAll(c); }
+        public boolean removeAll(Collection<?> c)   { return q.removeAll(c); }
+        public boolean retainAll(Collection<?> c)   { return q.retainAll(c); }
+        // We use inherited addAll; forwarding addAll would be wrong
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {q.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return q.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return q.spliterator();}
+        @Override
+        public Stream<E> stream()           {return q.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return q.parallelStream();}
+    }
+}
diff --git a/android-35/java/util/ComparableTimSort.java b/android-35/java/util/ComparableTimSort.java
new file mode 100644
index 0000000..7b90807
--- /dev/null
+++ b/android-35/java/util/ComparableTimSort.java
@@ -0,0 +1,907 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2009 Google Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This is a near duplicate of {@link TimSort}, modified for use with
+ * arrays of objects that implement {@link Comparable}, instead of using
+ * explicit comparators.
+ *
+ * <p>If you are using an optimizing VM, you may find that ComparableTimSort
+ * offers no performance benefit over TimSort in conjunction with a
+ * comparator that simply returns {@code ((Comparable)first).compareTo(Second)}.
+ * If this is the case, you are better off deleting ComparableTimSort to
+ * eliminate the code duplication.  (See Arrays.java for details.)
+ *
+ * @author Josh Bloch
+ */
+class ComparableTimSort {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final Object[] a;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private Object[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {
+        this.a = a;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            tmp = new Object[tlen];
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
+        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi);
+            binarySort(a, lo, hi, lo + initRunLen);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     */
+    @SuppressWarnings({"fallthrough", "rawtypes", "unchecked"})
+    private static void binarySort(Object[] a, int lo, int hi, int start) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            Comparable pivot = (Comparable) a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (pivot.compareTo(a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+     *        It is required that {@code lo < hi}.
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     *
+     * Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer,
+     * Richard Bubel and Reiner Hahnle, this is fixed with respect to
+     * the analysis in "On the Worst-Case Complexity of TimSort" by
+     * Nicolas Auger, Vincent Jug, Cyril Nicaud, and Carine Pivoteau.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] ||
+                n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+            } else if (n < 0 || runLen[n] > runLen[n + 1]) {
+                break; // Invariant is established
+            }
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    @SuppressWarnings("unchecked")
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight((Comparable<Object>) a[base2], a, base1, len1, 0);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft((Comparable<Object>) a[base1 + len1 - 1], a,
+                base2, len2, len2 - 1);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static int gallopLeft(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int lastOfs = 0;
+        int ofs = 1;
+        if (key.compareTo(a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static int gallopRight(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (key.compareTo(a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len1);
+
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (((Comparable) a[cursor2]).compareTo(tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight((Comparable) a[cursor2], tmp, cursor1, len1, 0);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1)  // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft((Comparable) tmp[cursor1], a, cursor2, len2, 0);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (((Comparable) tmp[cursor2]).compareTo(a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight((Comparable) tmp[cursor2], a, base1, len1, len1 - 1);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, tmpBase, len2, len2 - 1);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)
+                        break outer; // len2 == 1 || len2 == 0
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private Object[]  ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = -1 >>> Integer.numberOfLeadingZeros(minCapacity);
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            Object[] newArray = new Object[newSize];
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+
+}
diff --git a/android-35/java/util/Comparator.java b/android-35/java/util/Comparator.java
new file mode 100644
index 0000000..6e0420d
--- /dev/null
+++ b/android-35/java/util/Comparator.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.Comparators;
+
+/**
+ * A comparison function, which imposes a <i>total ordering</i> on
+ * some collection of objects.  Comparators can be passed to a sort
+ * method (such as {@link Collections#sort(List,Comparator)
+ * Collections.sort} or {@link Arrays#sort(Object[],Comparator)
+ * Arrays.sort}) to allow precise control over the sort order.
+ * Comparators can also be used to control the order of certain data
+ * structures (such as {@linkplain SortedSet sorted sets} or
+ * {@linkplain SortedMap sorted maps}), or to provide an ordering for
+ * collections of objects that don't have a {@linkplain Comparable
+ * natural ordering}.<p>
+ *
+ * The ordering imposed by a comparator {@code c} on a set of elements
+ * {@code S} is said to be <i>consistent with equals</i> if and only if
+ * {@code c.compare(e1, e2)==0} has the same boolean value as
+ * {@code e1.equals(e2)} for every {@code e1} and {@code e2} in
+ * {@code S}.<p>
+ *
+ * Caution should be exercised when using a comparator capable of imposing an
+ * ordering inconsistent with equals to order a sorted set (or sorted map).
+ * Suppose a sorted set (or sorted map) with an explicit comparator {@code c}
+ * is used with elements (or keys) drawn from a set {@code S}.  If the
+ * ordering imposed by {@code c} on {@code S} is inconsistent with equals,
+ * the sorted set (or sorted map) will behave "strangely."  In particular the
+ * sorted set (or sorted map) will violate the general contract for set (or
+ * map), which is defined in terms of {@code equals}.<p>
+ *
+ * For example, suppose one adds two elements {@code a} and {@code b} such that
+ * {@code (a.equals(b) && c.compare(a, b) != 0)}
+ * to an empty {@code TreeSet} with comparator {@code c}.
+ * The second {@code add} operation will return
+ * true (and the size of the tree set will increase) because {@code a} and
+ * {@code b} are not equivalent from the tree set's perspective, even though
+ * this is contrary to the specification of the
+ * {@link Set#add Set.add} method.<p>
+ *
+ * Note: It is generally a good idea for comparators to also implement
+ * {@code java.io.Serializable}, as they may be used as ordering methods in
+ * serializable data structures (like {@link TreeSet}, {@link TreeMap}).  In
+ * order for the data structure to serialize successfully, the comparator (if
+ * provided) must implement {@code Serializable}.<p>
+ *
+ * For the mathematically inclined, the <i>relation</i> that defines the
+ * <i>imposed ordering</i> that a given comparator {@code c} imposes on a
+ * given set of objects {@code S} is:<pre>
+ *       {(x, y) such that c.compare(x, y) &lt;= 0}.
+ * </pre> The <i>quotient</i> for this total order is:<pre>
+ *       {(x, y) such that c.compare(x, y) == 0}.
+ * </pre>
+ *
+ * It follows immediately from the contract for {@code compare} that the
+ * quotient is an <i>equivalence relation</i> on {@code S}, and that the
+ * imposed ordering is a <i>total order</i> on {@code S}.  When we say that
+ * the ordering imposed by {@code c} on {@code S} is <i>consistent with
+ * equals</i>, we mean that the quotient for the ordering is the equivalence
+ * relation defined by the objects' {@link Object#equals(Object)
+ * equals(Object)} method(s):<pre>
+ *     {(x, y) such that x.equals(y)}. </pre>
+ *
+ * In other words, when the imposed ordering is consistent with
+ * equals, the equivalence classes defined by the equivalence relation
+ * of the {@code equals} method and the equivalence classes defined by
+ * the quotient of the {@code compare} method are the same.
+
+ * <p>Unlike {@code Comparable}, a comparator may optionally permit
+ * comparison of null arguments, while maintaining the requirements for
+ * an equivalence relation.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <T> the type of objects that may be compared by this comparator
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Comparable
+ * @see java.io.Serializable
+ * @since 1.2
+ */
+@FunctionalInterface
+public interface Comparator<T> {
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     *
+     * The implementor must ensure that {@link Integer#signum
+     * signum}{@code (compare(x, y)) == -signum(compare(y, x))} for
+     * all {@code x} and {@code y}.  (This implies that {@code
+     * compare(x, y)} must throw an exception if and only if {@code
+     * compare(y, x)} throws an exception.)<p>
+     *
+     * The implementor must also ensure that the relation is transitive:
+     * {@code ((compare(x, y)>0) && (compare(y, z)>0))} implies
+     * {@code compare(x, z)>0}.<p>
+     *
+     * Finally, the implementor must ensure that {@code compare(x,
+     * y)==0} implies that {@code signum(compare(x,
+     * z))==signum(compare(y, z))} for all {@code z}.
+     *
+     * @apiNote
+     * It is generally the case, but <i>not</i> strictly required that
+     * {@code (compare(x, y)==0) == (x.equals(y))}.  Generally speaking,
+     * any comparator that violates this condition should clearly indicate
+     * this fact.  The recommended language is "Note: this comparator
+     * imposes orderings that are inconsistent with equals."
+     *
+     * @param o1 the first object to be compared.
+     * @param o2 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     *         first argument is less than, equal to, or greater than the
+     *         second.
+     * @throws NullPointerException if an argument is null and this
+     *         comparator does not permit null arguments
+     * @throws ClassCastException if the arguments' types prevent them from
+     *         being compared by this comparator.
+     */
+    int compare(T o1, T o2);
+
+    /**
+     * Indicates whether some other object is &quot;equal to&quot;
+     * this comparator.  This method must obey the general contract of
+     * {@link Object#equals(Object)}.  Additionally, this method can
+     * return {@code true} <i>only</i> if the specified object is also
+     * a comparator and it imposes the same ordering as this
+     * comparator.  Thus, {@code comp1.equals(comp2)} implies that
+     * {@link Integer#signum signum}{@code (comp1.compare(o1,
+     * o2))==signum(comp2.compare(o1, o2))} for every object reference
+     * {@code o1} and {@code o2}.<p>
+     *
+     * Note that it is <i>always</i> safe <i>not</i> to override
+     * {@code Object.equals(Object)}.  However, overriding this method may,
+     * in some cases, improve performance by allowing programs to determine
+     * that two distinct comparators impose the same order.
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  {@code true} only if the specified object is also
+     *          a comparator and it imposes the same ordering as this
+     *          comparator.
+     * @see Object#equals(Object)
+     * @see Object#hashCode()
+     */
+    boolean equals(Object obj);
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of this
+     * comparator.
+     *
+     * @return a comparator that imposes the reverse ordering of this
+     *         comparator.
+     * @since 1.8
+     */
+    default Comparator<T> reversed() {
+        return Collections.reverseOrder(this);
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with another comparator.
+     * If this {@code Comparator} considers two elements equal, i.e.
+     * {@code compare(a, b) == 0}, {@code other} is used to determine the order.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to sort a collection of {@code String} based on the length
+     * and then case-insensitive natural ordering, the comparator can be
+     * composed using following code,
+     *
+     * <pre>{@code
+     *     Comparator<String> cmp = Comparator.comparingInt(String::length)
+     *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  other the other comparator to be used when this comparator
+     *         compares two objects that are equal.
+     * @return a lexicographic-order comparator composed of this and then the
+     *         other comparator
+     * @throws NullPointerException if the argument is null.
+     * @since 1.8
+     */
+    default Comparator<T> thenComparing(Comparator<? super T> other) {
+        Objects.requireNonNull(other);
+        return (Comparator<T> & Serializable) (c1, c2) -> {
+            int res = compare(c1, c2);
+            return (res != 0) ? res : other.compare(c1, c2);
+        };
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a key to be compared with the given {@code Comparator}.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor, cmp))}.
+     *
+     * @param  <U>  the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a lexicographic-order comparator composed of this comparator
+     *         and then comparing on the key extracted by the keyExtractor function
+     * @throws NullPointerException if either argument is null.
+     * @see #comparing(Function, Comparator)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        return thenComparing(comparing(keyExtractor, keyComparator));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code Comparable} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor))}.
+     *
+     * @param  <U>  the type of the {@link Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@link Comparable} sort key.
+     * @throws NullPointerException if the argument is null.
+     * @see #comparing(Function)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        return thenComparing(comparing(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts an {@code int} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingInt(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code int} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingInt(ToIntFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
+        return thenComparing(comparingInt(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code long} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingLong(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code long} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingLong(ToLongFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
+        return thenComparing(comparingLong(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code double} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingDouble(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code double} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingDouble(ToDoubleFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        return thenComparing(comparingDouble(keyExtractor));
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em>.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on {@code Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
+        return Collections.reverseOrder();
+    }
+
+    /**
+     * Returns a comparator that compares {@link Comparable} objects in natural
+     * order.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the <i>natural ordering</i> on {@code
+     *         Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
+        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * less than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be less than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(true, comparator);
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * greater than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be greater than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(false, comparator);
+    }
+
+    /**
+     * Accepts a function that extracts a sort key from a type {@code T}, and
+     * returns a {@code Comparator<T>} that compares by that sort key using
+     * the specified {@link Comparator}.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * and comparator are both serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name ignoring case differences,
+     *
+     * <pre>{@code
+     *     Comparator<Person> cmp = Comparator.comparing(
+     *             Person::getLastName,
+     *             String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a comparator that compares by an extracted key using the
+     *         specified {@code Comparator}
+     * @throws NullPointerException if either argument is null
+     * @since 1.8
+     */
+    public static <T, U> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        Objects.requireNonNull(keyExtractor);
+        Objects.requireNonNull(keyComparator);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
+                                              keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@link java.lang.Comparable
+     * Comparable} sort key from a type {@code T}, and returns a {@code
+     * Comparator<T>} that compares by that sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name,
+     *
+     * <pre>{@code
+     *     Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the {@code Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a comparator that compares by an extracted key
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts an {@code int} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code long} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function is
+     * also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code double} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
+    }
+}
diff --git a/android-35/java/util/Comparators.java b/android-35/java/util/Comparators.java
new file mode 100644
index 0000000..bca2bb6
--- /dev/null
+++ b/android-35/java/util/Comparators.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Package private supporting class for {@link Comparator}.
+ */
+class Comparators {
+    private Comparators() {
+        throw new AssertionError("no instances");
+    }
+
+    /**
+     * Compares {@link Comparable} objects in natural order.
+     *
+     * @see Comparable
+     */
+    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
+        INSTANCE;
+
+        @Override
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c1.compareTo(c2);
+        }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.reverseOrder();
+        }
+    }
+
+    /**
+     * Null-friendly comparators
+     */
+    static final class NullComparator<T> implements Comparator<T>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -7569533591570686392L;
+        private final boolean nullFirst;
+        // if null, non-null Ts are considered equal
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        private final Comparator<T> real;
+
+        @SuppressWarnings("unchecked")
+        NullComparator(boolean nullFirst, Comparator<? super T> real) {
+            this.nullFirst = nullFirst;
+            this.real = (Comparator<T>) real;
+        }
+
+        @Override
+        public int compare(T a, T b) {
+            if (a == null) {
+                return (b == null) ? 0 : (nullFirst ? -1 : 1);
+            } else if (b == null) {
+                return nullFirst ? 1: -1;
+            } else {
+                return (real == null) ? 0 : real.compare(a, b);
+            }
+        }
+
+        @Override
+        public Comparator<T> thenComparing(Comparator<? super T> other) {
+            Objects.requireNonNull(other);
+            return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other));
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());
+        }
+    }
+}
diff --git a/android-35/java/util/ConcurrentModificationException.java b/android-35/java/util/ConcurrentModificationException.java
new file mode 100644
index 0000000..7161225
--- /dev/null
+++ b/android-35/java/util/ConcurrentModificationException.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This exception may be thrown by methods that have detected concurrent
+ * modification of an object when such modification is not permissible.
+ * <p>
+ * For example, it is not generally permissible for one thread to modify a Collection
+ * while another thread is iterating over it.  In general, the results of the
+ * iteration are undefined under these circumstances.  Some Iterator
+ * implementations (including those of all the general purpose collection implementations
+ * provided by the JRE) may choose to throw this exception if this behavior is
+ * detected.  Iterators that do this are known as <i>fail-fast</i> iterators,
+ * as they fail quickly and cleanly, rather that risking arbitrary,
+ * non-deterministic behavior at an undetermined time in the future.
+ * <p>
+ * Note that this exception does not always indicate that an object has
+ * been concurrently modified by a <i>different</i> thread.  If a single
+ * thread issues a sequence of method invocations that violates the
+ * contract of an object, the object may throw this exception.  For
+ * example, if a thread modifies a collection directly while it is
+ * iterating over the collection with a fail-fast iterator, the iterator
+ * will throw this exception.
+ *
+ * <p>Note that fail-fast behavior cannot be guaranteed as it is, generally
+ * speaking, impossible to make any hard guarantees in the presence of
+ * unsynchronized concurrent modification.  Fail-fast operations
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>{@code ConcurrentModificationException}
+ * should be used only to detect bugs.</i>
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Iterator
+ * @see     Spliterator
+ * @see     ListIterator
+ * @see     Vector
+ * @see     LinkedList
+ * @see     HashSet
+ * @see     Hashtable
+ * @see     TreeMap
+ * @see     AbstractList
+ * @since   1.2
+ */
+public class ConcurrentModificationException extends RuntimeException {
+    @java.io.Serial
+    private static final long serialVersionUID = -3666751008965953603L;
+
+    /**
+     * Constructs a ConcurrentModificationException with no
+     * detail message.
+     */
+    public ConcurrentModificationException() {
+    }
+
+    /**
+     * Constructs a {@code ConcurrentModificationException} with the
+     * specified detail message.
+     *
+     * @param message the detail message pertaining to this exception.
+     */
+    public ConcurrentModificationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.7
+     */
+    public ConcurrentModificationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with {@code cause} is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.7
+     */
+    public ConcurrentModificationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/android-35/java/util/Currency.java b/android-35/java/util/Currency.java
new file mode 100644
index 0000000..b2daecd
--- /dev/null
+++ b/android-35/java/util/Currency.java
@@ -0,0 +1,1229 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.stream.Collectors;
+
+import sun.util.logging.PlatformLogger;
+
+import libcore.icu.ICU;
+
+// BEGIN Android-changed: Removed docs about superseding runtime currency data.
+// Doing so via a properties file is not supported on Android.
+/**
+ * Represents a currency. Currencies are identified by their ISO 4217 currency
+ * codes. Visit the <a href="http://www.iso.org/iso/home/standards/currency_codes.htm">
+ * ISO web site</a> for more information.
+ * <p>
+ * The class is designed so that there's never more than one
+ * {@code Currency} instance for any given currency. Therefore, there's
+ * no public constructor. You obtain a {@code Currency} instance using
+ * the {@code getInstance} methods.
+ *
+ * <p>
+ * It is recommended to use {@link java.math.BigDecimal} class while dealing
+ * with {@code Currency} or monetary values as it provides better handling of floating
+ * point numbers and their operations.
+ *
+ * @see java.math.BigDecimal
+ * @since 1.4
+ */
+// END Android-changed: Removed docs about superseding runtime currency data.
+@SuppressWarnings("removal")
+public final class Currency implements Serializable {
+
+    @java.io.Serial
+    private static final long serialVersionUID = -158308464356906721L;
+
+    /**
+     * ISO 4217 currency code for this currency.
+     *
+     * @serial
+     */
+    private final String currencyCode;
+
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    /**
+     * Default fraction digits for this currency.
+     * Set from currency data tables.
+     *
+    private final transient int defaultFractionDigits;
+     */
+
+    /*
+     * ISO 4217 numeric code for this currency.
+     * Set from currency data tables.
+     *
+     private final transient int numericCode;
+     */
+    private transient final android.icu.util.Currency icuCurrency;
+    // END Android-changed: Use ICU.
+
+
+    // class data: instance map
+
+    private static ConcurrentMap<String, Currency> instances = new ConcurrentHashMap<>(7);
+    private static HashSet<Currency> available;
+
+    // BEGIN Android-removed: Use ICU.
+    // We don't need any of these static fields nor the static initializer.
+    /*
+    // Class data: currency data obtained from currency.data file.
+    // Purpose:
+    // - determine valid country codes
+    // - determine valid currency codes
+    // - map country codes to currency codes
+    // - obtain default fraction digits for currency codes
+    //
+    // sc = special case; dfd = default fraction digits
+    // Simple countries are those where the country code is a prefix of the
+    // currency code, and there are no known plans to change the currency.
+    //
+    // table formats:
+    // - mainTable:
+    //   - maps country code to 32-bit int
+    //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
+    //   - \u007F -> not valid country
+    //   - bits 20-31: unused
+    //   - bits 10-19: numeric code (0 to 1023)
+    //   - bit 9: 1 - special case, bits 0-4 indicate which one
+    //            0 - simple country, bits 0-4 indicate final char of currency code
+    //   - bits 5-8: fraction digits for simple countries, 0 for special cases
+    //   - bits 0-4: final char for currency code for simple country, or ID of special case
+    // - special case IDs:
+    //   - 0: country has no currency
+    //   - other: index into specialCasesList
+
+    static int formatVersion;
+    static int dataVersion;
+    static int[] mainTable;
+    static List<SpecialCaseEntry> specialCasesList;
+    static List<OtherCurrencyEntry> otherCurrenciesList;
+
+    // handy constants - must match definitions in GenerateCurrencyData
+    // magic number
+    private static final int MAGIC_NUMBER = 0x43757244;
+    // number of characters from A to Z
+    private static final int A_TO_Z = ('Z' - 'A') + 1;
+    // entry for invalid country codes
+    private static final int INVALID_COUNTRY_ENTRY = 0x0000007F;
+    // entry for countries without currency
+    private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200;
+    // mask for simple case country entries
+    private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000;
+    // mask for simple case country entry final character
+    private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F;
+    // mask for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0;
+    // shift count for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
+    // maximum number for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9;
+    // mask for special case country entries
+    private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200;
+    // mask for special case country index
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F;
+    // delta from entry index component in main table to index into special case tables
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
+    // mask for distinguishing simple and special case countries
+    private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
+    // mask for the numeric code of the currency
+    private static final int NUMERIC_CODE_MASK = 0x000FFC00;
+    // shift count for the numeric code of the currency
+    private static final int NUMERIC_CODE_SHIFT = 10;
+
+    // Currency data format version
+    private static final int VALID_FORMAT_VERSION = 3;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<>() {
+            @Override
+            public Void run() {
+                try {
+                    try (InputStream in = getClass().getResourceAsStream("/java/util/currency.data")) {
+                        if (in == null) {
+                            throw new InternalError("Currency data not found");
+                        }
+                        DataInputStream dis = new DataInputStream(new BufferedInputStream(in));
+                        if (dis.readInt() != MAGIC_NUMBER) {
+                            throw new InternalError("Currency data is possibly corrupted");
+                        }
+                        formatVersion = dis.readInt();
+                        if (formatVersion != VALID_FORMAT_VERSION) {
+                            throw new InternalError("Currency data format is incorrect");
+                        }
+                        dataVersion = dis.readInt();
+                        mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
+                        int scCount = dis.readInt();
+                        specialCasesList = readSpecialCases(dis, scCount);
+                        int ocCount = dis.readInt();
+                        otherCurrenciesList = readOtherCurrencies(dis, ocCount);
+                    }
+                } catch (IOException e) {
+                    throw new InternalError(e);
+                }
+
+                // look for the properties file for overrides
+                String propsFile = System.getProperty("java.util.currency.data");
+                if (propsFile == null) {
+                    propsFile = StaticProperty.javaHome() + File.separator + "lib" +
+                        File.separator + "currency.properties";
+                }
+                try {
+                    File propFile = new File(propsFile);
+                    if (propFile.exists()) {
+                        Properties props = new Properties();
+                        try (FileReader fr = new FileReader(propFile)) {
+                            props.load(fr);
+                        }
+                        Pattern propertiesPattern =
+                                Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*" +
+                                        "(\\d+)\\s*,?\\s*(\\d{4}-\\d{2}-\\d{2}T\\d{2}:" +
+                                        "\\d{2}:\\d{2})?");
+                        List<CurrencyProperty> currencyEntries
+                                = getValidCurrencyData(props, propertiesPattern);
+                        currencyEntries.forEach(Currency::replaceCurrencyData);
+                    }
+                } catch (IOException e) {
+                    CurrencyProperty.info("currency.properties is ignored"
+                            + " because of an IOException", e);
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Constants for retrieving localized names from the name providers.
+     *
+    private static final int SYMBOL = 0;
+    private static final int DISPLAYNAME = 1;
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Constructs a {@code Currency} instance. The constructor is private
+     * so that we can insure that there's never more than one instance for a
+     * given currency.
+     */
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
+        this.currencyCode = currencyCode;
+        this.defaultFractionDigits = defaultFractionDigits;
+        this.numericCode = numericCode;
+    }
+    */
+    private Currency(android.icu.util.Currency icuCurrency) {
+        this.icuCurrency = icuCurrency;
+        this.currencyCode = icuCurrency.getCurrencyCode();
+    }
+    // END Android-changed: Use ICU.
+
+    /**
+     * Returns the {@code Currency} instance for the given currency code.
+     *
+     * @param currencyCode the ISO 4217 code of the currency
+     * @return the {@code Currency} instance for the given currency code
+     * @throws    NullPointerException if {@code currencyCode} is null
+     * @throws    IllegalArgumentException if {@code currencyCode} is not
+     * a supported ISO 4217 code.
+     */
+    public static Currency getInstance(String currencyCode) {
+        // BEGIN Android-changed: Use ICU.
+        // Upstream uses a private static helper method, implemented differently.
+        Currency instance = instances.get(currencyCode);
+        if (instance != null) {
+            return instance;
+        }
+        android.icu.util.Currency icuInstance =
+                  android.icu.util.Currency.getInstance(currencyCode);
+        if (icuInstance == null) {
+            return null;
+        }
+        /*
+        if (defaultFractionDigits == Integer.MIN_VALUE) {
+            // Currency code not internally generated, need to verify first
+            // A currency code must have 3 characters and exist in the main table
+            // or in the list of other currencies.
+            boolean found = false;
+            if (currencyCode.length() != 3) {
+                throw new IllegalArgumentException();
+            }
+            char char1 = currencyCode.charAt(0);
+            char char2 = currencyCode.charAt(1);
+            int tableEntry = getMainTableEntry(char1, char2);
+            if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                    && tableEntry != INVALID_COUNTRY_ENTRY
+                    && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
+                defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+                numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+                found = true;
+            } else { //special case
+                int[] fractionAndNumericCode = SpecialCaseEntry.findEntry(currencyCode);
+                if (fractionAndNumericCode != null) {
+                    defaultFractionDigits = fractionAndNumericCode[0];
+                    numericCode = fractionAndNumericCode[1];
+                    found = true;
+                }
+            }
+
+            if (!found) {
+                OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode);
+                if (ocEntry == null) {
+                    throw new IllegalArgumentException();
+                }
+                defaultFractionDigits = ocEntry.fraction;
+                numericCode = ocEntry.numericCode;
+            }
+        }
+        */
+
+        Currency currencyVal = new Currency(icuInstance);
+        // END Android-changed: Use ICU.
+        instance = instances.putIfAbsent(currencyCode, currencyVal);
+        return (instance != null ? instance : currencyVal);
+    }
+
+    // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
+    /**
+     * Returns the {@code Currency} instance for the country of the
+     * given locale. The language and variant components of the locale
+     * are ignored. The result may vary over time, as countries change their
+     * currencies. For example, for the original member countries of the
+     * European Monetary Union, the method returns the old national currencies
+     * until December 31, 2001, and the Euro from January 1, 2002, local time
+     * of the respective countries.
+     * <p>
+     * If the specified {@code locale} contains "cu"
+     * <a href="./Locale.html#def_locale_extension">Unicode extensions</a>,
+     * the instance returned from this method reflects
+     * the values specified with those extensions.
+     * <p>
+     * The method returns {@code null} for territories that don't
+     * have a currency, such as Antarctica.
+     *
+     * @param locale the locale for whose country a {@code Currency}
+     * instance is needed
+     * @return the {@code Currency} instance for the country of the given
+     * locale, or {@code null}
+     * @throws    NullPointerException if {@code locale}
+     * is {@code null}
+     * @throws    IllegalArgumentException if the country of the given {@code locale}
+     * is not a supported ISO 3166 country code.
+     */
+    public static Currency getInstance(Locale locale) {
+        // check for locale overrides
+        String override = locale.getUnicodeLocaleType("cu");
+        if (override != null) {
+            try {
+                return getInstance(override.toUpperCase(Locale.ROOT));
+            } catch (IllegalArgumentException iae) {
+                // override currency is invalid. Fall through.
+            }
+        }
+
+        // BEGIN Android-changed: Use ICU.
+        /*
+        String country = CalendarDataUtility.findRegionOverride(locale).getCountry();
+
+        if (country == null || !country.matches("^[a-zA-Z]{2}$")) {
+            throw new IllegalArgumentException();
+        }
+
+        char char1 = country.charAt(0);
+        char char2 = country.charAt(1);
+        int tableEntry = getMainTableEntry(char1, char2);
+        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                    && tableEntry != INVALID_COUNTRY_ENTRY) {
+            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+            StringBuilder sb = new StringBuilder(country);
+            sb.append(finalChar);
+            return getInstance(sb.toString(), defaultFractionDigits, numericCode);
+        } else {
+            // special cases
+            if (tableEntry == INVALID_COUNTRY_ENTRY) {
+                throw new IllegalArgumentException();
+            }
+            if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
+                return null;
+            } else {
+                int index = SpecialCaseEntry.toIndex(tableEntry);
+                SpecialCaseEntry scEntry = specialCasesList.get(index);
+                if (scEntry.cutOverTime == Long.MAX_VALUE
+                        || System.currentTimeMillis() < scEntry.cutOverTime) {
+                    return getInstance(scEntry.oldCurrency,
+                            scEntry.oldCurrencyFraction,
+                            scEntry.oldCurrencyNumericCode);
+                } else {
+                    return getInstance(scEntry.newCurrency,
+                            scEntry.newCurrencyFraction,
+                            scEntry.newCurrencyNumericCode);
+                }
+            }
+        }
+        */
+        String country = locale.getCountry();
+        android.icu.util.Currency icuInstance =
+                android.icu.util.Currency.getInstance(locale);
+        // Unknown historical reason to append variant to country code. The API documentation
+        // does not mention the effect of locale variant. The actual effect here is throwing
+        // IllegalArgumentException because the code like FR_EURO is not a valid country code.
+        String variant = locale.getVariant();
+        if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
+                variant.equals("PREEURO"))) {
+            country = country + "_" + variant;
+        }
+        if (!ICU.isIsoCountry(country)) {
+            // Throws IllegalArgumentException as required by the API documentation.
+            throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
+        }
+        String currencyCode = ICU.getCurrencyCode(country);
+        if (currencyCode == null || icuInstance == null ||
+                icuInstance.getCurrencyCode().equals("XXX")) { // XXX is not a real currency.
+            return null;
+        }
+        return getInstance(currencyCode);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the set of available currencies.  The returned set of currencies
+     * contains all of the available currencies, which may include currencies
+     * that represent obsolete ISO 4217 codes.  The set can be modified
+     * without affecting the available currencies in the runtime.
+     *
+     * @return the set of available currencies.  If there is no currency
+     *    available in the runtime, the returned set is empty.
+     * @since 1.7
+     */
+    public static Set<Currency> getAvailableCurrencies() {
+        synchronized(Currency.class) {
+            if (available == null) {
+                // BEGIN Android-changed: Use ICU.
+                /*
+                available = new HashSet<>(256);
+
+                // Add simple currencies first
+                for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
+                    for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
+                        int tableEntry = getMainTableEntry(c1, c2);
+                        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                             && tableEntry != INVALID_COUNTRY_ENTRY) {
+                            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+                            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+                            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+                            StringBuilder sb = new StringBuilder();
+                            sb.append(c1);
+                            sb.append(c2);
+                            sb.append(finalChar);
+                            available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
+                        } else if ((tableEntry & COUNTRY_TYPE_MASK) == SPECIAL_CASE_COUNTRY_MASK
+                                && tableEntry != INVALID_COUNTRY_ENTRY
+                                && tableEntry != COUNTRY_WITHOUT_CURRENCY_ENTRY) {
+                            int index = SpecialCaseEntry.toIndex(tableEntry);
+                            SpecialCaseEntry scEntry = specialCasesList.get(index);
+
+                            if (scEntry.cutOverTime == Long.MAX_VALUE
+                                    || System.currentTimeMillis() < scEntry.cutOverTime) {
+                                available.add(getInstance(scEntry.oldCurrency,
+                                        scEntry.oldCurrencyFraction,
+                                        scEntry.oldCurrencyNumericCode));
+                            } else {
+                                available.add(getInstance(scEntry.newCurrency,
+                                        scEntry.newCurrencyFraction,
+                                        scEntry.newCurrencyNumericCode));
+                            }
+                        }
+                    }
+                }
+
+                // Now add other currencies
+                for (OtherCurrencyEntry entry : otherCurrenciesList) {
+                    available.add(getInstance(entry.currencyCode));
+                }
+                */
+                available = new HashSet<>();
+                Set<android.icu.util.Currency> icuAvailableCurrencies
+                        = android.icu.util.Currency.getAvailableCurrencies();
+                for (android.icu.util.Currency icuCurrency : icuAvailableCurrencies) {
+                    Currency currency = getInstance(icuCurrency.getCurrencyCode());
+                    if (currency == null) {
+                        currency = new Currency(icuCurrency);
+                        instances.put(currency.currencyCode, currency);
+                    }
+                    available.add(currency);
+                }
+                // END Android-changed: Use ICU.
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        Set<Currency> result = (Set<Currency>) available.clone();
+        return result;
+    }
+
+    /**
+     * Gets the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency.
+     */
+    public String getCurrencyCode() {
+        return currencyCode;
+    }
+
+    // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
+    /**
+     * Gets the symbol of this currency for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, for the US Dollar, the symbol is "$" if the default
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getSymbol(Locale)
+     *     getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the symbol of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     */
+    public String getSymbol() {
+        return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    // Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
+    /**
+     * Gets the symbol of this currency for the specified locale.
+     * For example, for the US Dollar, the symbol is "$" if the specified
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the symbol of this currency for the specified locale
+     * @throws    NullPointerException if {@code locale} is null
+     */
+    public String getSymbol(Locale locale) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        locale = CalendarDataUtility.findRegionOverride(locale);
+        String symbol = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, SYMBOL);
+        if (symbol != null) {
+            return symbol;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        if (locale == null) {
+            throw new NullPointerException("locale == null");
+        }
+        return icuCurrency.getSymbol(locale);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the default number of fraction digits used with this currency.
+     * Note that the number of fraction digits is the same as ISO 4217's
+     * minor unit for the currency.
+     * For example, the default number of fraction digits for the Euro is 2,
+     * while for the Japanese Yen it's 0.
+     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
+     * -1 is returned.
+     *
+     * @return the default number of fraction digits used with this currency
+     */
+    public int getDefaultFractionDigits() {
+        // BEGIN Android-changed: Use ICU.
+        // return defaultFractionDigits;
+        if (icuCurrency.getCurrencyCode().equals("XXX")) {
+            return -1;
+        }
+        return icuCurrency.getDefaultFractionDigits();
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns the ISO 4217 numeric code of this currency.
+     *
+     * @return the ISO 4217 numeric code of this currency
+     * @since 1.7
+     */
+    public int getNumericCode() {
+        // Android-changed: Use ICU.
+        // return numericCode;
+        return icuCurrency.getNumericCode();
+    }
+
+    /**
+     * Returns the 3 digit ISO 4217 numeric code of this currency as a {@code String}.
+     * Unlike {@link #getNumericCode()}, which returns the numeric code as {@code int},
+     * this method always returns the numeric code as a 3 digit string.
+     * e.g. a numeric value of 32 would be returned as "032",
+     * and a numeric value of 6 would be returned as "006".
+     *
+     * @return the 3 digit ISO 4217 numeric code of this currency as a {@code String}
+     * @since 9
+     */
+    public String getNumericCodeAsString() {
+        // Android-added: We don't store the code as a field. Call getNumericCode().
+        int numericCode = getNumericCode();
+        /* numeric code could be returned as a 3 digit string simply by using
+           String.format("%03d",numericCode); which uses regex to parse the format,
+           "%03d" in this case. Parsing a regex gives an extra performance overhead,
+           so String.format() approach is avoided in this scenario.
+        */
+        if (numericCode < 100) {
+            StringBuilder sb = new StringBuilder();
+            sb.append('0');
+            if (numericCode < 10) {
+                sb.append('0');
+            }
+            return sb.append(numericCode).toString();
+        }
+        return String.valueOf(numericCode);
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * If there is no suitable display name found
+     * for the default locale, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getDisplayName(Locale)
+     *     getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the display name of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayName() {
+        return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the specified locale.  If there is no suitable display name found
+     * for the specified locale, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the display name of this currency for the specified locale
+     * @throws    NullPointerException if {@code locale} is null
+     * @since 1.7
+     */
+    public String getDisplayName(Locale locale) {
+        // Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        String result = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, DISPLAYNAME);
+        if (result != null) {
+            return result;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        return icuCurrency.getDisplayName(Objects.requireNonNull(locale));
+    }
+
+    /**
+     * Returns the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency
+     */
+    @Override
+    public String toString() {
+        // Android-changed: Use ICU.
+        // return currencyCode;
+        return icuCurrency.toString();
+    }
+
+    /**
+     * Resolves instances being deserialized to a single instance per currency.
+     */
+    @java.io.Serial
+    private Object readResolve() {
+        return getInstance(currencyCode);
+    }
+
+    // Android-removed: Use ICU.
+    // Removed a bunch of private helper methods that are unused on Android.
+    /**
+     * Gets the main table entry for the country whose country code consists
+     * of char1 and char2.
+     *
+    private static int getMainTableEntry(char char1, char char2) {
+        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
+            throw new IllegalArgumentException();
+        }
+        return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
+    }
+
+    /**
+     * Sets the main table entry for the country whose country code consists
+     * of char1 and char2.
+     *
+    private static void setMainTableEntry(char char1, char char2, int entry) {
+        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
+            throw new IllegalArgumentException();
+        }
+        mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
+    }
+
+    /**
+     * Obtains a localized currency names from a CurrencyNameProvider
+     * implementation.
+     *
+    private static class CurrencyNameGetter
+        implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
+                                                                   String> {
+        private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
+
+        @Override
+        public String getObject(CurrencyNameProvider currencyNameProvider,
+                                Locale locale,
+                                String key,
+                                Object... params) {
+            assert params.length == 1;
+            int type = (Integer)params[0];
+
+            switch(type) {
+            case SYMBOL:
+                return currencyNameProvider.getSymbol(key, locale);
+            case DISPLAYNAME:
+                return currencyNameProvider.getDisplayName(key, locale);
+            default:
+                assert false; // shouldn't happen
+            }
+
+            return null;
+        }
+    }
+
+    private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
+        int[] ret = new int[count];
+        for (int i = 0; i < count; i++) {
+            ret[i] = dis.readInt();
+        }
+
+        return ret;
+    }
+
+    private static List<SpecialCaseEntry> readSpecialCases(DataInputStream dis,
+            int count)
+            throws IOException {
+
+        List<SpecialCaseEntry> list = new ArrayList<>(count);
+        long cutOverTime;
+        String oldCurrency;
+        String newCurrency;
+        int oldCurrencyFraction;
+        int newCurrencyFraction;
+        int oldCurrencyNumericCode;
+        int newCurrencyNumericCode;
+
+        for (int i = 0; i < count; i++) {
+            cutOverTime = dis.readLong();
+            oldCurrency = dis.readUTF();
+            newCurrency = dis.readUTF();
+            oldCurrencyFraction = dis.readInt();
+            newCurrencyFraction = dis.readInt();
+            oldCurrencyNumericCode = dis.readInt();
+            newCurrencyNumericCode = dis.readInt();
+            SpecialCaseEntry sc = new SpecialCaseEntry(cutOverTime,
+                    oldCurrency, newCurrency,
+                    oldCurrencyFraction, newCurrencyFraction,
+                    oldCurrencyNumericCode, newCurrencyNumericCode);
+            list.add(sc);
+        }
+        return list;
+    }
+
+    private static List<OtherCurrencyEntry> readOtherCurrencies(DataInputStream dis,
+            int count)
+            throws IOException {
+
+        List<OtherCurrencyEntry> list = new ArrayList<>(count);
+        String currencyCode;
+        int fraction;
+        int numericCode;
+
+        for (int i = 0; i < count; i++) {
+            currencyCode = dis.readUTF();
+            fraction = dis.readInt();
+            numericCode = dis.readInt();
+            OtherCurrencyEntry oc = new OtherCurrencyEntry(currencyCode,
+                    fraction,
+                    numericCode);
+            list.add(oc);
+        }
+        return list;
+    }
+
+    /**
+     * Parse currency data found in the properties file (that
+     * java.util.currency.data designates) to a List of CurrencyProperty
+     * instances. Also, remove invalid entries and the multiple currency
+     * code inconsistencies.
+     *
+     * @param props properties containing currency data
+     * @param pattern regex pattern for the properties entry
+     * @return list of parsed property entries
+     *
+    private static List<CurrencyProperty> getValidCurrencyData(Properties props,
+            Pattern pattern) {
+
+        Set<String> keys = props.stringPropertyNames();
+        List<CurrencyProperty> propertyEntries = new ArrayList<>();
+
+        // remove all invalid entries and parse all valid currency properties
+        // entries to a group of CurrencyProperty, classified by currency code
+        Map<String, List<CurrencyProperty>> currencyCodeGroup = keys.stream()
+                .map(k -> CurrencyProperty
+                .getValidEntry(k.toUpperCase(Locale.ROOT),
+                        props.getProperty(k).toUpperCase(Locale.ROOT),
+                        pattern)).flatMap(o -> o.stream())
+                .collect(Collectors.groupingBy(entry -> entry.currencyCode));
+
+        // check each group for inconsistencies
+        currencyCodeGroup.forEach((curCode, list) -> {
+            boolean inconsistent = CurrencyProperty
+                    .containsInconsistentInstances(list);
+            if (inconsistent) {
+                list.forEach(prop -> CurrencyProperty.info("The property"
+                        + " entry for " + prop.country + " is inconsistent."
+                        + " Ignored.", null));
+            } else {
+                propertyEntries.addAll(list);
+            }
+        });
+
+        return propertyEntries;
+    }
+
+    /**
+     * Replaces currency data found in the properties file that
+     * java.util.currency.data designates. This method is invoked for
+     * each valid currency entry.
+     *
+     * @param prop CurrencyProperty instance of the valid property entry
+     *
+    private static void replaceCurrencyData(CurrencyProperty prop) {
+
+
+        String ctry = prop.country;
+        String code = prop.currencyCode;
+        int numeric = prop.numericCode;
+        int fraction = prop.fraction;
+        int entry = numeric << NUMERIC_CODE_SHIFT;
+
+        int index = SpecialCaseEntry.indexOf(code, fraction, numeric);
+
+
+        // If a new entry changes the numeric code/dfd of an existing
+        // currency code, update it in the sc list at the respective
+        // index and also change it in the other currencies list and
+        // main table (if that currency code is also used as a
+        // simple case).
+
+        // If all three components do not match with the new entry,
+        // but the currency code exists in the special case list
+        // update the sc entry with the new entry
+        int scCurrencyCodeIndex = -1;
+        if (index == -1) {
+            scCurrencyCodeIndex = SpecialCaseEntry.currencyCodeIndex(code);
+            if (scCurrencyCodeIndex != -1) {
+                //currency code exists in sc list, then update the old entry
+                specialCasesList.set(scCurrencyCodeIndex,
+                        new SpecialCaseEntry(code, fraction, numeric));
+
+                // also update the entry in other currencies list
+                OtherCurrencyEntry oe = OtherCurrencyEntry.findEntry(code);
+                if (oe != null) {
+                    int oIndex = otherCurrenciesList.indexOf(oe);
+                    otherCurrenciesList.set(oIndex, new OtherCurrencyEntry(
+                            code, fraction, numeric));
+                }
+            }
+        }
+
+        /* If a country switches from simple case to special case or
+         * one special case to other special case which is not present
+         * in the sc arrays then insert the new entry in special case arrays.
+         * If an entry with given currency code exists, update with the new
+         * entry.
+         *
+        if (index == -1 && (ctry.charAt(0) != code.charAt(0)
+                || ctry.charAt(1) != code.charAt(1))) {
+
+            if(scCurrencyCodeIndex == -1) {
+                specialCasesList.add(new SpecialCaseEntry(code, fraction,
+                        numeric));
+                index = specialCasesList.size() - 1;
+            } else {
+                index = scCurrencyCodeIndex;
+            }
+
+            // update the entry in main table if it exists as a simple case
+            updateMainTableEntry(code, fraction, numeric);
+        }
+
+        if (index == -1) {
+            // simple case
+            entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT)
+                    | (code.charAt(2) - 'A');
+        } else {
+            // special case
+            entry = SPECIAL_CASE_COUNTRY_MASK
+                    | (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
+        }
+        setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
+    }
+
+    // update the entry in maintable for any simple case found, if a new
+    // entry as a special case updates the entry in sc list with
+    // existing currency code
+    private static void updateMainTableEntry(String code, int fraction,
+            int numeric) {
+        // checking the existence of currency code in mainTable
+        int tableEntry = getMainTableEntry(code.charAt(0), code.charAt(1));
+        int entry = numeric << NUMERIC_CODE_SHIFT;
+        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                && tableEntry != INVALID_COUNTRY_ENTRY
+                && code.charAt(2) - 'A' == (tableEntry
+                & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
+
+            int numericCode = (tableEntry & NUMERIC_CODE_MASK)
+                    >> NUMERIC_CODE_SHIFT;
+            int defaultFractionDigits = (tableEntry
+                    & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK)
+                    >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+            if (numeric != numericCode || fraction != defaultFractionDigits) {
+                // update the entry in main table
+                entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT)
+                        | (code.charAt(2) - 'A');
+                setMainTableEntry(code.charAt(0), code.charAt(1), entry);
+            }
+        }
+    }
+
+    /* Used to represent a special case currency entry
+     * - cutOverTime: cut-over time in millis as returned by
+     *   System.currentTimeMillis for special case countries that are changing
+     *   currencies; Long.MAX_VALUE for countries that are not changing currencies
+     * - oldCurrency: old currencies for special case countries
+     * - newCurrency: new currencies for special case countries that are
+     *   changing currencies; null for others
+     * - oldCurrencyFraction: default fraction digits for old currencies
+     * - newCurrencyFraction: default fraction digits for new currencies, 0 for
+     *   countries that are not changing currencies
+     * - oldCurrencyNumericCode: numeric code for old currencies
+     * - newCurrencyNumericCode: numeric code for new currencies, 0 for countries
+     *   that are not changing currencies
+    *
+    private static class SpecialCaseEntry {
+
+        private final long cutOverTime;
+        private final String oldCurrency;
+        private final String newCurrency;
+        private final int oldCurrencyFraction;
+        private final int newCurrencyFraction;
+        private final int oldCurrencyNumericCode;
+        private final int newCurrencyNumericCode;
+
+        private SpecialCaseEntry(long cutOverTime, String oldCurrency, String newCurrency,
+                int oldCurrencyFraction, int newCurrencyFraction,
+                int oldCurrencyNumericCode, int newCurrencyNumericCode) {
+            this.cutOverTime = cutOverTime;
+            this.oldCurrency = oldCurrency;
+            this.newCurrency = newCurrency;
+            this.oldCurrencyFraction = oldCurrencyFraction;
+            this.newCurrencyFraction = newCurrencyFraction;
+            this.oldCurrencyNumericCode = oldCurrencyNumericCode;
+            this.newCurrencyNumericCode = newCurrencyNumericCode;
+        }
+
+        private SpecialCaseEntry(String currencyCode, int fraction,
+                int numericCode) {
+            this(Long.MAX_VALUE, currencyCode, "", fraction, 0, numericCode, 0);
+        }
+
+        //get the index of the special case entry
+        private static int indexOf(String code, int fraction, int numeric) {
+            int size = specialCasesList.size();
+            for (int index = 0; index < size; index++) {
+                SpecialCaseEntry scEntry = specialCasesList.get(index);
+                if (scEntry.oldCurrency.equals(code)
+                        && scEntry.oldCurrencyFraction == fraction
+                        && scEntry.oldCurrencyNumericCode == numeric
+                        && scEntry.cutOverTime == Long.MAX_VALUE) {
+                    return index;
+                }
+            }
+            return -1;
+        }
+
+        // get the fraction and numericCode of the sc currencycode
+        private static int[] findEntry(String code) {
+            int[] fractionAndNumericCode = null;
+            int size = specialCasesList.size();
+            for (int index = 0; index < size; index++) {
+                SpecialCaseEntry scEntry = specialCasesList.get(index);
+                if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE
+                        || System.currentTimeMillis() < scEntry.cutOverTime)) {
+                    //consider only when there is no new currency or cutover time is not passed
+                    fractionAndNumericCode = new int[2];
+                    fractionAndNumericCode[0] = scEntry.oldCurrencyFraction;
+                    fractionAndNumericCode[1] = scEntry.oldCurrencyNumericCode;
+                    break;
+                } else if (scEntry.newCurrency.equals(code)
+                        && System.currentTimeMillis() >= scEntry.cutOverTime) {
+                    //consider only if the cutover time is passed
+                    fractionAndNumericCode = new int[2];
+                    fractionAndNumericCode[0] = scEntry.newCurrencyFraction;
+                    fractionAndNumericCode[1] = scEntry.newCurrencyNumericCode;
+                    break;
+                }
+            }
+            return fractionAndNumericCode;
+        }
+
+        // get the index based on currency code
+        private static int currencyCodeIndex(String code) {
+            int size = specialCasesList.size();
+            for (int index = 0; index < size; index++) {
+                SpecialCaseEntry scEntry = specialCasesList.get(index);
+                if (scEntry.oldCurrency.equals(code) && (scEntry.cutOverTime == Long.MAX_VALUE
+                        || System.currentTimeMillis() < scEntry.cutOverTime)) {
+                    //consider only when there is no new currency or cutover time is not passed
+                    return index;
+                } else if (scEntry.newCurrency.equals(code)
+                        && System.currentTimeMillis() >= scEntry.cutOverTime) {
+                    //consider only if the cutover time is passed
+                    return index;
+                }
+            }
+            return -1;
+        }
+
+
+        // convert the special case entry to sc arrays index
+        private static int toIndex(int tableEntry) {
+            return (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
+        }
+
+    }
+
+    /* Used to represent Other currencies
+     * - currencyCode: currency codes that are not the main currency
+     *   of a simple country
+     * - otherCurrenciesDFD: decimal format digits for other currencies
+     * - otherCurrenciesNumericCode: numeric code for other currencies
+     *
+    private static class OtherCurrencyEntry {
+
+        private final String currencyCode;
+        private final int fraction;
+        private final int numericCode;
+
+        private OtherCurrencyEntry(String currencyCode, int fraction,
+                int numericCode) {
+            this.currencyCode = currencyCode;
+            this.fraction = fraction;
+            this.numericCode = numericCode;
+        }
+
+        //get the instance of the other currency code
+        private static OtherCurrencyEntry findEntry(String code) {
+            int size = otherCurrenciesList.size();
+            for (int index = 0; index < size; index++) {
+                OtherCurrencyEntry ocEntry = otherCurrenciesList.get(index);
+                if (ocEntry.currencyCode.equalsIgnoreCase(code)) {
+                    return ocEntry;
+                }
+            }
+            return null;
+        }
+
+    }
+
+
+    /*
+     * Used to represent an entry of the properties file that
+     * java.util.currency.data designates
+     *
+     * - country: country representing the currency entry
+     * - currencyCode: currency code
+     * - fraction: default fraction digit
+     * - numericCode: numeric code
+     * - date: cutover date
+     *
+    private static class CurrencyProperty {
+        private final String country;
+        private final String currencyCode;
+        private final int fraction;
+        private final int numericCode;
+        private final String date;
+
+        private CurrencyProperty(String country, String currencyCode,
+                int fraction, int numericCode, String date) {
+            this.country = country;
+            this.currencyCode = currencyCode;
+            this.fraction = fraction;
+            this.numericCode = numericCode;
+            this.date = date;
+        }
+
+        /**
+         * Check the valid currency data and create/return an Optional instance
+         * of CurrencyProperty
+         *
+         * @param ctry    country representing the currency data
+         * @param curData currency data of the given {@code ctry}
+         * @param pattern regex pattern for the properties entry
+         * @return Optional containing CurrencyProperty instance, If valid;
+         *         empty otherwise
+         *
+        private static Optional<CurrencyProperty> getValidEntry(String ctry,
+                String curData,
+                Pattern pattern) {
+
+            CurrencyProperty prop = null;
+
+            if (ctry.length() != 2) {
+                // Invalid country code. Ignore the entry.
+            } else {
+
+                prop = parseProperty(ctry, curData, pattern);
+                // if the property entry failed any of the below checked
+                // criteria it is ignored
+                if (prop == null
+                        || (prop.date == null && curData.chars()
+                                .map(c -> c == ',' ? 1 : 0).sum() >= 3)) {
+                    // format is not recognized.  ignore the data if date
+                    // string is null and we've 4 values, bad date value
+                    prop = null;
+                } else if (prop.fraction
+                        > SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS) {
+                    prop = null;
+                } else {
+                    try {
+                        if (prop.date != null
+                                && !isPastCutoverDate(prop.date)) {
+                            prop = null;
+                        }
+                    } catch (ParseException ex) {
+                        prop = null;
+                    }
+                }
+            }
+
+            if (prop == null) {
+                info("The property entry for " + ctry + " is invalid."
+                        + " Ignored.", null);
+            }
+
+            return Optional.ofNullable(prop);
+        }
+
+        /*
+         * Parse properties entry and return CurrencyProperty instance
+         *
+        private static CurrencyProperty parseProperty(String ctry,
+                String curData, Pattern pattern) {
+            Matcher m = pattern.matcher(curData);
+            if (!m.find()) {
+                return null;
+            } else {
+                return new CurrencyProperty(ctry, m.group(1),
+                        Integer.parseInt(m.group(3)),
+                        Integer.parseInt(m.group(2)), m.group(4));
+            }
+        }
+
+        /**
+         * Checks if the given list contains multiple inconsistent currency instances
+         *
+        private static boolean containsInconsistentInstances(
+                List<CurrencyProperty> list) {
+            int numCode = list.get(0).numericCode;
+            int fractionDigit = list.get(0).fraction;
+            return list.stream().anyMatch(prop -> prop.numericCode != numCode
+                    || prop.fraction != fractionDigit);
+        }
+
+        private static boolean isPastCutoverDate(String s)
+                throws ParseException {
+            SimpleDateFormat format = new SimpleDateFormat(
+                    "yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT);
+            format.setTimeZone(TimeZone.getTimeZone("UTC"));
+            format.setLenient(false);
+            long time = format.parse(s.trim()).getTime();
+            return System.currentTimeMillis() > time;
+
+        }
+
+        private static void info(String message, Throwable t) {
+            PlatformLogger logger = PlatformLogger
+                    .getLogger("java.util.Currency");
+            if (logger.isLoggable(PlatformLogger.Level.INFO)) {
+                if (t != null) {
+                    logger.info(message, t);
+                } else {
+                    logger.info(message);
+                }
+            }
+        }
+
+    }
+    */
+}
diff --git a/android-35/java/util/Date.java b/android-35/java/util/Date.java
new file mode 100644
index 0000000..494bb4d
--- /dev/null
+++ b/android-35/java/util/Date.java
@@ -0,0 +1,1400 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.text.DateFormat;
+import java.time.LocalDate;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.lang.ref.SoftReference;
+import java.time.Instant;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+
+/**
+ * The class {@code Date} represents a specific instant
+ * in time, with millisecond precision.
+ * <p>
+ * Prior to JDK&nbsp;1.1, the class {@code Date} had two additional
+ * functions.  It allowed the interpretation of dates as year, month, day, hour,
+ * minute, and second values.  It also allowed the formatting and parsing
+ * of date strings.  Unfortunately, the API for these functions was not
+ * amenable to internationalization.  As of JDK&nbsp;1.1, the
+ * {@code Calendar} class should be used to convert between dates and time
+ * fields and the {@code DateFormat} class should be used to format and
+ * parse date strings.
+ * The corresponding methods in {@code Date} are deprecated.
+ * <p>
+ * Although the {@code Date} class is intended to reflect
+ * coordinated universal time (UTC), it may not do so exactly,
+ * depending on the host environment of the Java Virtual Machine.
+ * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
+ * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds
+ * in all cases. In UTC, however, about once every year or two there
+ * is an extra second, called a "leap second." The leap
+ * second is always added as the last second of the day, and always
+ * on December 31 or June 30. For example, the last minute of the
+ * year 1995 was 61 seconds long, thanks to an added leap second.
+ * Most computer clocks are not accurate enough to be able to reflect
+ * the leap-second distinction.
+ * <p>
+ * Some computer standards are defined in terms of Greenwich mean
+ * time (GMT), which is equivalent to universal time (UT).  GMT is
+ * the "civil" name for the standard; UT is the
+ * "scientific" name for the same standard. The
+ * distinction between UTC and UT is that UTC is based on an atomic
+ * clock and UT is based on astronomical observations, which for all
+ * practical purposes is an invisibly fine hair to split. Because the
+ * earth's rotation is not uniform (it slows down and speeds up
+ * in complicated ways), UT does not always flow uniformly. Leap
+ * seconds are introduced as needed into UTC so as to keep UTC within
+ * 0.9 seconds of UT1, which is a version of UT with certain
+ * corrections applied. There are other time and date systems as
+ * well; for example, the time scale used by the satellite-based
+ * global positioning system (GPS) is synchronized to UTC but is
+ * <i>not</i> adjusted for leap seconds. An interesting source of
+ * further information is the United States Naval Observatory (USNO):
+ * <blockquote><pre>
+ *     <a href="https://www.usno.navy.mil/USNO">https://www.usno.navy.mil/USNO</a>
+ * </pre></blockquote>
+ * <p>
+ * and the material regarding "Systems of Time" at:
+ * <blockquote><pre>
+ *     <a href="https://www.usno.navy.mil/USNO/time/master-clock/systems-of-time">https://www.usno.navy.mil/USNO/time/master-clock/systems-of-time</a>
+ * </pre></blockquote>
+ * <p>
+ * which has descriptions of various different time systems including
+ * UT, UT1, and UTC.
+ * <p>
+ * In all methods of class {@code Date} that accept or return
+ * year, month, date, hours, minutes, and seconds values, the
+ * following representations are used:
+ * <ul>
+ * <li>A year <i>y</i> is represented by the integer
+ *     <i>y</i>&nbsp;{@code - 1900}.
+ * <li>A month is represented by an integer from 0 to 11; 0 is January,
+ *     1 is February, and so forth; thus 11 is December.
+ * <li>A date (day of month) is represented by an integer from 1 to 31
+ *     in the usual manner.
+ * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
+ *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1
+ *     p.m. is hour 12.
+ * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
+ * <li>A second is represented by an integer from 0 to 61; the values 60 and
+ *     61 occur only for leap seconds and even then only in Java
+ *     implementations that actually track leap seconds correctly. Because
+ *     of the manner in which leap seconds are currently introduced, it is
+ *     extremely unlikely that two leap seconds will occur in the same
+ *     minute, but this specification follows the date and time conventions
+ *     for ISO C.
+ * </ul>
+ * <p>
+ * In all cases, arguments given to methods for these purposes need
+ * not fall within the indicated ranges; for example, a date may be
+ * specified as January 32 and is interpreted as meaning February 1.
+ *
+ * @author  James Gosling
+ * @author  Arthur van Hoff
+ * @author  Alan Liu
+ * @see     java.text.DateFormat
+ * @see     java.util.Calendar
+ * @see     java.util.TimeZone
+ * @since   1.0
+ */
+public class Date
+    implements java.io.Serializable, Cloneable, Comparable<Date>
+{
+    private static final BaseCalendar gcal =
+                                CalendarSystem.getGregorianCalendar();
+    private static BaseCalendar jcal;
+
+    private transient long fastTime;
+
+    /*
+     * If cdate is null, then fastTime indicates the time in millis.
+     * If cdate.isNormalized() is true, then fastTime and cdate are in
+     * synch. Otherwise, fastTime is ignored, and cdate indicates the
+     * time.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    // Initialized just before the value is used. See parse().
+    private static int defaultCenturyStart;
+
+    /* use serialVersionUID from modified java.util.Date for
+     * interoperability with JDK1.1. The Date was modified to write
+     * and read only the UTC time.
+     */
+    @java.io.Serial
+    private static final long serialVersionUID = 7523967970034938905L;
+
+    /**
+     * Allocates a {@code Date} object and initializes it so that
+     * it represents the time at which it was allocated, measured to the
+     * nearest millisecond.
+     *
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date() {
+        this(System.currentTimeMillis());
+    }
+
+    /**
+     * Allocates a {@code Date} object and initializes it to
+     * represent the specified number of milliseconds since the
+     * standard base time known as "the epoch", namely January 1,
+     * 1970, 00:00:00 GMT.
+     *
+     * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date(long date) {
+        fastTime = date;
+    }
+
+    /**
+     * Allocates a {@code Date} object and initializes it so that
+     * it represents midnight, local time, at the beginning of the day
+     * specified by the {@code year}, {@code month}, and
+     * {@code date} arguments.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(year + 1900, month, date)}
+     * or {@code GregorianCalendar(year + 1900, month, date)}.
+     */
+    @Deprecated
+    public Date(int year, int month, int date) {
+        this(year, month, date, 0, 0, 0);
+    }
+
+    /**
+     * Allocates a {@code Date} object and initializes it so that
+     * it represents the instant at the start of the minute specified by
+     * the {@code year}, {@code month}, {@code date},
+     * {@code hrs}, and {@code min} arguments, in the local
+     * time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(year + 1900, month, date, hrs, min)}
+     * or {@code GregorianCalendar(year + 1900, month, date, hrs, min)}.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min) {
+        this(year, month, date, hrs, min, 0);
+    }
+
+    /**
+     * Allocates a {@code Date} object and initializes it so that
+     * it represents the instant at the start of the second specified
+     * by the {@code year}, {@code month}, {@code date},
+     * {@code hrs}, {@code min}, and {@code sec} arguments,
+     * in the local time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(year + 1900, month, date, hrs, min, sec)}
+     * or {@code GregorianCalendar(year + 1900, month, date, hrs, min, sec)}.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar cal = getCalendarSystem(y);
+        cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+        cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
+        getTimeImpl();
+        cdate = null;
+    }
+
+    /**
+     * Allocates a {@code Date} object and initializes it so that
+     * it represents the date and time indicated by the string
+     * {@code s}, which is interpreted as if by the
+     * {@link Date#parse} method.
+     *
+     * @param   s   a string representation of the date.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#parse(java.lang.String)
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code DateFormat.parse(String s)}.
+     */
+    @Deprecated
+    public Date(String s) {
+        this(parse(s));
+    }
+
+    /**
+     * Return a copy of this object.
+     */
+    public Object clone() {
+        Date d = null;
+        try {
+            d = (Date)super.clone();
+            if (cdate != null) {
+                d.cdate = (BaseCalendar.Date) cdate.clone();
+            }
+        } catch (CloneNotSupportedException e) {} // Won't happen
+        return d;
+    }
+
+    /**
+     * Determines the date and time based on the arguments. The
+     * arguments are interpreted as a year, month, day of the month,
+     * hour of the day, minute within the hour, and second within the
+     * minute, exactly as for the {@code Date} constructor with six
+     * arguments, except that the arguments are interpreted relative
+     * to UTC rather than to the local time zone. The time indicated is
+     * returned represented as the distance, measured in milliseconds,
+     * of that time from the epoch (00:00:00 GMT on January 1, 1970).
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
+     *          the date and time specified by the arguments.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(year + 1900, month, date, hrs, min, sec)}
+     * or {@code GregorianCalendar(year + 1900, month, date, hrs, min, sec)}, using a UTC
+     * {@code TimeZone}, followed by {@code Calendar.getTime().getTime()}.
+     */
+    @Deprecated
+    public static long UTC(int year, int month, int date,
+                           int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        int m = month + 1;
+        BaseCalendar cal = getCalendarSystem(y);
+        BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
+        udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
+
+        // Use a Date instance to perform normalization. Its fastTime
+        // is the UTC value after the normalization.
+        Date d = new Date(0);
+        d.normalize(udate);
+        return d.fastTime;
+    }
+
+    /**
+     * Attempts to interpret the string {@code s} as a representation
+     * of a date and time. If the attempt is successful, the time
+     * indicated is returned represented as the distance, measured in
+     * milliseconds, of that time from the epoch (00:00:00 GMT on
+     * January 1, 1970). If the attempt fails, an
+     * {@code IllegalArgumentException} is thrown.
+     * <p>
+     * It accepts many syntaxes; in particular, it recognizes the IETF
+     * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
+     * understands the continental U.S. time-zone abbreviations, but for
+     * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
+     * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
+     * meridian). If no time zone is specified, the local time zone is
+     * assumed. GMT and UTC are considered equivalent.
+     * <p>
+     * The string {@code s} is processed from left to right, looking for
+     * data of interest. Any material in {@code s} that is within the
+     * ASCII parenthesis characters {@code (} and {@code )} is ignored.
+     * Parentheses may be nested. Otherwise, the only characters permitted
+     * within {@code s} are these ASCII characters:
+     * <blockquote><pre>
+     * abcdefghijklmnopqrstuvwxyz
+     * ABCDEFGHIJKLMNOPQRSTUVWXYZ
+     * 0123456789,+-:/</pre></blockquote>
+     * and whitespace characters.<p>
+     * A consecutive sequence of decimal digits is treated as a decimal
+     * number:<ul>
+     * <li>If a number is preceded by {@code +} or {@code -} and a year
+     *     has already been recognized, then the number is a time-zone
+     *     offset. If the number is less than 24, it is an offset measured
+     *     in hours. Otherwise, it is regarded as an offset in minutes,
+     *     expressed in 24-hour time format without punctuation. A
+     *     preceding {@code -} means a westward offset. Time zone offsets
+     *     are always relative to UTC (Greenwich). Thus, for example,
+     *     {@code -5} occurring in the string would mean "five hours west
+     *     of Greenwich" and {@code +0430} would mean "four hours and
+     *     thirty minutes east of Greenwich." It is permitted for the
+     *     string to specify {@code GMT}, {@code UT}, or {@code UTC}
+     *     redundantly-for example, {@code GMT-5} or {@code utc+0430}.
+     * <li>The number is regarded as a year number if one of the
+     *     following conditions is true:
+     * <ul>
+     *     <li>The number is equal to or greater than 70 and followed by a
+     *         space, comma, slash, or end of string
+     *     <li>The number is less than 70, and both a month and a day of
+     *         the month have already been recognized</li>
+     * </ul>
+     *     If the recognized year number is less than 100, it is
+     *     interpreted as an abbreviated year relative to a century of
+     *     which dates are within 80 years before and 19 years after
+     *     the time when the Date class is initialized.
+     *     After adjusting the year number, 1900 is subtracted from
+     *     it. For example, if the current year is 1999 then years in
+     *     the range 19 to 99 are assumed to mean 1919 to 1999, while
+     *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
+     *     that this is slightly different from the interpretation of
+     *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
+     * <li>If the number is followed by a colon, it is regarded as an hour,
+     *     unless an hour has already been recognized, in which case it is
+     *     regarded as a minute.
+     * <li>If the number is followed by a slash, it is regarded as a month
+     *     (it is decreased by 1 to produce a number in the range {@code 0}
+     *     to {@code 11}), unless a month has already been recognized, in
+     *     which case it is regarded as a day of the month.
+     * <li>If the number is followed by whitespace, a comma, a hyphen, or
+     *     end of string, then if an hour has been recognized but not a
+     *     minute, it is regarded as a minute; otherwise, if a minute has
+     *     been recognized but not a second, it is regarded as a second;
+     *     otherwise, it is regarded as a day of the month. </ul><p>
+     * A consecutive sequence of letters is regarded as a word and treated
+     * as follows:<ul>
+     * <li>A word that matches {@code AM}, ignoring case, is ignored (but
+     *     the parse fails if an hour has not been recognized or is less
+     *     than {@code 1} or greater than {@code 12}).
+     * <li>A word that matches {@code PM}, ignoring case, adds {@code 12}
+     *     to the hour (but the parse fails if an hour has not been
+     *     recognized or is less than {@code 1} or greater than {@code 12}).
+     * <li>Any word that matches any prefix of {@code SUNDAY, MONDAY, TUESDAY,
+     *     WEDNESDAY, THURSDAY, FRIDAY}, or {@code SATURDAY}, ignoring
+     *     case, is ignored. For example, {@code sat, Friday, TUE}, and
+     *     {@code Thurs} are ignored.
+     * <li>Otherwise, any word that matches any prefix of {@code JANUARY,
+     *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
+     *     OCTOBER, NOVEMBER}, or {@code DECEMBER}, ignoring case, and
+     *     considering them in the order given here, is recognized as
+     *     specifying a month and is converted to a number ({@code 0} to
+     *     {@code 11}). For example, {@code aug, Sept, april}, and
+     *     {@code NOV} are recognized as months. So is {@code Ma}, which
+     *     is recognized as {@code MARCH}, not {@code MAY}.
+     * <li>Any word that matches {@code GMT, UT}, or {@code UTC}, ignoring
+     *     case, is treated as referring to UTC.
+     * <li>Any word that matches {@code EST, CST, MST}, or {@code PST},
+     *     ignoring case, is recognized as referring to the time zone in
+     *     North America that is five, six, seven, or eight hours west of
+     *     Greenwich, respectively. Any word that matches {@code EDT, CDT,
+     *     MDT}, or {@code PDT}, ignoring case, is recognized as
+     *     referring to the same time zone, respectively, during daylight
+     *     saving time.</ul><p>
+     * Once the entire string s has been scanned, it is converted to a time
+     * result in one of two ways. If a time zone or time-zone offset has been
+     * recognized, then the year, month, day of month, hour, minute, and
+     * second are interpreted in UTC and then the time-zone offset is
+     * applied. Otherwise, the year, month, day of month, hour, minute, and
+     * second are interpreted in the local time zone.
+     *
+     * @param   s   a string to be parsed as a date.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by the string argument.
+     * @see     java.text.DateFormat
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code DateFormat.parse(String s)}.
+     */
+    @Deprecated
+    public static long parse(String s) {
+        int year = Integer.MIN_VALUE;
+        int mon = -1;
+        int mday = -1;
+        int hour = -1;
+        int min = -1;
+        int sec = -1;
+        int millis = -1;
+        int c = -1;
+        int i = 0;
+        int n = -1;
+        int wst = -1;
+        int tzoffset = -1;
+        int prevc = 0;
+    syntax:
+        {
+            if (s == null)
+                break syntax;
+            int limit = s.length();
+            while (i < limit) {
+                c = s.charAt(i);
+                i++;
+                if (c <= ' ' || c == ',')
+                    continue;
+                if (c == '(') { // skip comments
+                    int depth = 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        i++;
+                        if (c == '(') depth++;
+                        else if (c == ')')
+                            if (--depth <= 0)
+                                break;
+                    }
+                    continue;
+                }
+                if ('0' <= c && c <= '9') {
+                    n = c - '0';
+                    while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                        n = n * 10 + c - '0';
+                        i++;
+                    }
+                    if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
+                        // BEGIN Android-changed: Android specific time zone logic
+
+                        if (tzoffset != 0 && tzoffset != -1)
+                            break syntax;
+
+                        // timezone offset
+                        if (n < 24) {
+                            n = n * 60; // EG. "GMT-3"
+
+                            // Support for Timezones of the form GMT-3:30. We look for an ':" and
+                            // parse the number following it as loosely as the original hours
+                            // section (i.e, no range or validity checks).
+                            int minutesPart = 0;
+                            if (i < limit && (s.charAt(i) == ':')) {
+                                i++;
+                                while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                                    minutesPart = (minutesPart * 10) + (c - '0');
+                                    i++;
+                                }
+                            }
+
+                            n += minutesPart;
+                        } else {
+                            n = (n % 100) + ((n / 100) * 60); // eg "GMT-0430"
+                        }
+
+                        if (prevc == '+')   // plus means east of GMT
+                            n = -n;
+                        // END Android-changed: Android specific time zone logic
+
+                        tzoffset = n;
+                    } else if (n >= 70)
+                        if (year != Integer.MIN_VALUE)
+                            break syntax;
+                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
+                            // year = n < 1900 ? n : n - 1900;
+                            year = n;
+                        else
+                            break syntax;
+                    else if (c == ':')
+                        if (hour < 0)
+                            hour = (byte) n;
+                        else if (min < 0)
+                            min = (byte) n;
+                        else
+                            break syntax;
+                    else if (c == '/')
+                        if (mon < 0)
+                            mon = (byte) (n - 1);
+                        else if (mday < 0)
+                            mday = (byte) n;
+                        else
+                            break syntax;
+                    else if (i < limit && c != ',' && c > ' ' && c != '-')
+                        break syntax;
+                    else if (hour >= 0 && min < 0)
+                        min = (byte) n;
+                    else if (min >= 0 && sec < 0)
+                        sec = (byte) n;
+                    else if (mday < 0)
+                        mday = (byte) n;
+                    // Handle two-digit years < 70 (70-99 handled above).
+                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
+                        year = n;
+                    else
+                        break syntax;
+                    prevc = 0;
+                } else if (c == '/' || c == ':' || c == '+' || c == '-')
+                    prevc = c;
+                else {
+                    int st = i - 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
+                            break;
+                        i++;
+                    }
+                    if (i <= st + 1)
+                        break syntax;
+                    int k;
+                    for (k = wtb.length; --k >= 0;)
+                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
+                            int action = ttb[k];
+                            if (action != 0) {
+                                if (action == 1) {  // pm
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour < 12)
+                                        hour += 12;
+                                } else if (action == 14) {  // am
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour == 12)
+                                        hour = 0;
+                                } else if (action <= 13) {  // month!
+                                    if (mon < 0)
+                                        mon = (byte) (action - 2);
+                                    else
+                                        break syntax;
+                                } else {
+                                    tzoffset = action - 10000;
+                                }
+                            }
+                            break;
+                        }
+                    if (k < 0)
+                        break syntax;
+                    prevc = 0;
+                }
+            }
+            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
+                break syntax;
+            // Parse 2-digit years within the correct default century.
+            if (year < 100) {
+                synchronized (Date.class) {
+                    if (defaultCenturyStart == 0) {
+                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
+                    }
+                }
+                year += (defaultCenturyStart / 100) * 100;
+                if (year < defaultCenturyStart) year += 100;
+            }
+            if (sec < 0)
+                sec = 0;
+            if (min < 0)
+                min = 0;
+            if (hour < 0)
+                hour = 0;
+            BaseCalendar cal = getCalendarSystem(year);
+            if (tzoffset == -1)  { // no time zone specified, have to use local
+                BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+                ldate.setDate(year, mon + 1, mday);
+                ldate.setTimeOfDay(hour, min, sec, 0);
+                return cal.getTime(ldate);
+            }
+            BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
+            udate.setDate(year, mon + 1, mday);
+            udate.setTimeOfDay(hour, min, sec, 0);
+            return cal.getTime(udate) + tzoffset * (60 * 1000);
+        }
+        // syntax error
+        throw new IllegalArgumentException();
+    }
+    private static final String wtb[] = {
+        "am", "pm",
+        "monday", "tuesday", "wednesday", "thursday", "friday",
+        "saturday", "sunday",
+        "january", "february", "march", "april", "may", "june",
+        "july", "august", "september", "october", "november", "december",
+        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
+        "mst", "mdt", "pst", "pdt"
+    };
+    private static final int ttb[] = {
+        14, 1, 0, 0, 0, 0, 0, 0, 0,
+        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
+        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
+        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
+        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
+        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
+    };
+
+    /**
+     * Returns a value that is the result of subtracting 1900 from the
+     * year that contains or begins with the instant in time represented
+     * by this {@code Date} object, as interpreted in the local
+     * time zone.
+     *
+     * @return  the year represented by this date, minus 1900.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.YEAR) - 1900}.
+     */
+    @Deprecated
+    public int getYear() {
+        return normalize().getYear() - 1900;
+    }
+
+    /**
+     * Sets the year of this {@code Date} object to be the specified
+     * value plus 1900. This {@code Date} object is modified so
+     * that it represents a point in time within the specified year,
+     * with the month, date, hour, minute, and second the same as
+     * before, as interpreted in the local time zone. (Of course, if
+     * the date was February 29, for example, and the year is set to a
+     * non-leap year, then the new date will be treated as if it were
+     * on March 1.)
+     *
+     * @param   year    the year value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.YEAR, year + 1900)}.
+     */
+    @Deprecated
+    public void setYear(int year) {
+        getCalendarDate().setNormalizedYear(year + 1900);
+    }
+
+    /**
+     * Returns a number representing the month that contains or begins
+     * with the instant in time represented by this {@code Date} object.
+     * The value returned is between {@code 0} and {@code 11},
+     * with the value {@code 0} representing January.
+     *
+     * @return  the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.MONTH)}.
+     */
+    @Deprecated
+    public int getMonth() {
+        return normalize().getMonth() - 1; // adjust 1-based to 0-based
+    }
+
+    /**
+     * Sets the month of this date to the specified value. This
+     * {@code Date} object is modified so that it represents a point
+     * in time within the specified month, with the year, date, hour,
+     * minute, and second the same as before, as interpreted in the
+     * local time zone. If the date was October 31, for example, and
+     * the month is set to June, then the new date will be treated as
+     * if it were on July 1, because June has only 30 days.
+     *
+     * @param   month   the month value between 0-11.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.MONTH, int month)}.
+     */
+    @Deprecated
+    public void setMonth(int month) {
+        int y = 0;
+        if (month >= 12) {
+            y = month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y = CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar.Date d = getCalendarDate();
+        if (y != 0) {
+            d.setNormalizedYear(d.getNormalizedYear() + y);
+        }
+        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
+    }
+
+    /**
+     * Returns the day of the month represented by this {@code Date} object.
+     * The value returned is between {@code 1} and {@code 31}
+     * representing the day of the month that contains or begins with the
+     * instant in time represented by this {@code Date} object, as
+     * interpreted in the local time zone.
+     *
+     * @return  the day of the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.DAY_OF_MONTH)}.
+     */
+    @Deprecated
+    public int getDate() {
+        return normalize().getDayOfMonth();
+    }
+
+    /**
+     * Sets the day of the month of this {@code Date} object to the
+     * specified value. This {@code Date} object is modified so that
+     * it represents a point in time within the specified day of the
+     * month, with the year, month, hour, minute, and second the same
+     * as before, as interpreted in the local time zone. If the date
+     * was April 30, for example, and the date is set to 31, then it
+     * will be treated as if it were on May 1, because April has only
+     * 30 days.
+     *
+     * @param   date   the day of the month value between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.DAY_OF_MONTH, int date)}.
+     */
+    @Deprecated
+    public void setDate(int date) {
+        getCalendarDate().setDayOfMonth(date);
+    }
+
+    /**
+     * Returns the day of the week represented by this date. The
+     * returned value ({@code 0} = Sunday, {@code 1} = Monday,
+     * {@code 2} = Tuesday, {@code 3} = Wednesday, {@code 4} =
+     * Thursday, {@code 5} = Friday, {@code 6} = Saturday)
+     * represents the day of the week that contains or begins with
+     * the instant in time represented by this {@code Date} object,
+     * as interpreted in the local time zone.
+     *
+     * @return  the day of the week represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.DAY_OF_WEEK)}.
+     */
+    @Deprecated
+    public int getDay() {
+        return normalize().getDayOfWeek() - BaseCalendar.SUNDAY;
+    }
+
+    /**
+     * Returns the hour represented by this {@code Date} object. The
+     * returned value is a number ({@code 0} through {@code 23})
+     * representing the hour within the day that contains or begins
+     * with the instant in time represented by this {@code Date}
+     * object, as interpreted in the local time zone.
+     *
+     * @return  the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.HOUR_OF_DAY)}.
+     */
+    @Deprecated
+    public int getHours() {
+        return normalize().getHours();
+    }
+
+    /**
+     * Sets the hour of this {@code Date} object to the specified value.
+     * This {@code Date} object is modified so that it represents a point
+     * in time within the specified hour of the day, with the year, month,
+     * date, minute, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   hours   the hour value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.HOUR_OF_DAY, int hours)}.
+     */
+    @Deprecated
+    public void setHours(int hours) {
+        getCalendarDate().setHours(hours);
+    }
+
+    /**
+     * Returns the number of minutes past the hour represented by this date,
+     * as interpreted in the local time zone.
+     * The value returned is between {@code 0} and {@code 59}.
+     *
+     * @return  the number of minutes past the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.MINUTE)}.
+     */
+    @Deprecated
+    public int getMinutes() {
+        return normalize().getMinutes();
+    }
+
+    /**
+     * Sets the minutes of this {@code Date} object to the specified value.
+     * This {@code Date} object is modified so that it represents a point
+     * in time within the specified minute of the hour, with the year, month,
+     * date, hour, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   minutes   the value of the minutes.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.MINUTE, int minutes)}.
+     */
+    @Deprecated
+    public void setMinutes(int minutes) {
+        getCalendarDate().setMinutes(minutes);
+    }
+
+    /**
+     * Returns the number of seconds past the minute represented by this date.
+     * The value returned is between {@code 0} and {@code 61}. The
+     * values {@code 60} and {@code 61} can only occur on those
+     * Java Virtual Machines that take leap seconds into account.
+     *
+     * @return  the number of seconds past the minute represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.get(Calendar.SECOND)}.
+     */
+    @Deprecated
+    public int getSeconds() {
+        return normalize().getSeconds();
+    }
+
+    /**
+     * Sets the seconds of this {@code Date} to the specified value.
+     * This {@code Date} object is modified so that it represents a
+     * point in time within the specified second of the minute, with
+     * the year, month, date, hour, and minute the same as before, as
+     * interpreted in the local time zone.
+     *
+     * @param   seconds   the seconds value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code Calendar.set(Calendar.SECOND, int seconds)}.
+     */
+    @Deprecated
+    public void setSeconds(int seconds) {
+        getCalendarDate().setSeconds(seconds);
+    }
+
+    /**
+     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     * represented by this {@code Date} object.
+     *
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by this date.
+     */
+    public long getTime() {
+        return getTimeImpl();
+    }
+
+    private final long getTimeImpl() {
+        if (cdate != null && !cdate.isNormalized()) {
+            normalize();
+        }
+        return fastTime;
+    }
+
+    /**
+     * Sets this {@code Date} object to represent a point in time that is
+     * {@code time} milliseconds after January 1, 1970 00:00:00 GMT.
+     *
+     * @param   time   the number of milliseconds.
+     */
+    public void setTime(long time) {
+        fastTime = time;
+        cdate = null;
+    }
+
+    /**
+     * Tests if this date is before the specified date.
+     *
+     * @param   when   a date.
+     * @return  {@code true} if and only if the instant of time
+     *            represented by this {@code Date} object is strictly
+     *            earlier than the instant represented by {@code when};
+     *          {@code false} otherwise.
+     * @throws    NullPointerException if {@code when} is null.
+     */
+    public boolean before(Date when) {
+        return getMillisOf(this) < getMillisOf(when);
+    }
+
+    /**
+     * Tests if this date is after the specified date.
+     *
+     * @param   when   a date.
+     * @return  {@code true} if and only if the instant represented
+     *          by this {@code Date} object is strictly later than the
+     *          instant represented by {@code when};
+     *          {@code false} otherwise.
+     * @throws    NullPointerException if {@code when} is null.
+     */
+    public boolean after(Date when) {
+        return getMillisOf(this) > getMillisOf(when);
+    }
+
+    /**
+     * Compares two dates for equality.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and is a {@code Date} object that
+     * represents the same point in time, to the millisecond, as this object.
+     * <p>
+     * Thus, two {@code Date} objects are equal if and only if the
+     * {@code getTime} method returns the same {@code long}
+     * value for both.
+     *
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.util.Date#getTime()
+     */
+    public boolean equals(Object obj) {
+        return obj instanceof Date && getTime() == ((Date) obj).getTime();
+    }
+
+    /**
+     * Returns the millisecond value of this {@code Date} object
+     * without affecting its internal state.
+     */
+    static final long getMillisOf(Date date) {
+        if (date.getClass() != Date.class) {
+            return date.getTime();
+        }
+        if (date.cdate == null || date.cdate.isNormalized()) {
+            return date.fastTime;
+        }
+        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
+        return gcal.getTime(d);
+    }
+
+    /**
+     * Compares two Dates for ordering.
+     *
+     * @param   anotherDate   the {@code Date} to be compared.
+     * @return  the value {@code 0} if the argument Date is equal to
+     *          this Date; a value less than {@code 0} if this Date
+     *          is before the Date argument; and a value greater than
+     *      {@code 0} if this Date is after the Date argument.
+     * @since   1.2
+     * @throws    NullPointerException if {@code anotherDate} is null.
+     */
+    public int compareTo(Date anotherDate) {
+        long thisTime = getMillisOf(this);
+        long anotherTime = getMillisOf(anotherDate);
+        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
+    }
+
+    /**
+     * Returns a hash code value for this object. The result is the
+     * exclusive OR of the two halves of the primitive {@code long}
+     * value returned by the {@link Date#getTime}
+     * method. That is, the hash code is the value of the expression:
+     * <blockquote><pre>{@code
+     * (int)(this.getTime()^(this.getTime() >>> 32))
+     * }</pre></blockquote>
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        long ht = this.getTime();
+        return (int) ht ^ (int) (ht >> 32);
+    }
+
+    /**
+     * Converts this {@code Date} object to a {@code String}
+     * of the form:
+     * <blockquote><pre>
+     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
+     * where:<ul>
+     * <li>{@code dow} is the day of the week ({@code Sun, Mon, Tue, Wed,
+     *     Thu, Fri, Sat}).
+     * <li>{@code mon} is the month ({@code Jan, Feb, Mar, Apr, May, Jun,
+     *     Jul, Aug, Sep, Oct, Nov, Dec}).
+     * <li>{@code dd} is the day of the month ({@code 01} through
+     *     {@code 31}), as two decimal digits.
+     * <li>{@code hh} is the hour of the day ({@code 00} through
+     *     {@code 23}), as two decimal digits.
+     * <li>{@code mm} is the minute within the hour ({@code 00} through
+     *     {@code 59}), as two decimal digits.
+     * <li>{@code ss} is the second within the minute ({@code 00} through
+     *     {@code 61}, as two decimal digits.
+     * <li>{@code zzz} is the time zone (and may reflect daylight saving
+     *     time). Standard time zone abbreviations include those
+     *     recognized by the method {@code parse}. If time zone
+     *     information is not available, then {@code zzz} is empty -
+     *     that is, it consists of no characters at all.
+     * <li>{@code yyyy} is the year, as four decimal digits.
+     * </ul>
+     *
+     * @return  a string representation of this date.
+     * @see     java.util.Date#toLocaleString()
+     * @see     java.util.Date#toGMTString()
+     */
+    public String toString() {
+        // "EEE MMM dd HH:mm:ss zzz yyyy";
+        BaseCalendar.Date date = normalize();
+        StringBuilder sb = new StringBuilder(28);
+        int index = date.getDayOfWeek();
+        if (index == BaseCalendar.SUNDAY) {
+            index = 8;
+        }
+        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
+
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
+        TimeZone zi = date.getZone();
+        if (zi != null) {
+            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
+        } else {
+            sb.append("GMT");
+        }
+        sb.append(' ').append(date.getYear());  // yyyy
+        return sb.toString();
+    }
+
+    /**
+     * Converts the given name to its 3-letter abbreviation (e.g.,
+     * "monday" -> "Mon") and stored the abbreviation in the given
+     * {@code StringBuilder}.
+     */
+    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
+        sb.append(Character.toUpperCase(name.charAt(0)));
+        sb.append(name.charAt(1)).append(name.charAt(2));
+        return sb;
+    }
+
+    /**
+     * Creates a string representation of this {@code Date} object in an
+     * implementation-dependent form. The intent is that the form should
+     * be familiar to the user of the Java application, wherever it may
+     * happen to be running. The intent is comparable to that of the
+     * "{@code %c}" format supported by the {@code strftime()}
+     * function of ISO&nbsp;C.
+     *
+     * @return  a string representation of this date, using the locale
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toGMTString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code DateFormat.format(Date date)}.
+     */
+    @Deprecated
+    public String toLocaleString() {
+        DateFormat formatter = DateFormat.getDateTimeInstance();
+        return formatter.format(this);
+    }
+
+    /**
+     * Creates a string representation of this {@code Date} object of
+     * the form:
+     * <blockquote><pre>
+     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
+     * where:<ul>
+     * <li><i>d</i> is the day of the month ({@code 1} through {@code 31}),
+     *     as one or two decimal digits.
+     * <li><i>mon</i> is the month ({@code Jan, Feb, Mar, Apr, May, Jun, Jul,
+     *     Aug, Sep, Oct, Nov, Dec}).
+     * <li><i>yyyy</i> is the year, as four decimal digits.
+     * <li><i>hh</i> is the hour of the day ({@code 00} through {@code 23}),
+     *     as two decimal digits.
+     * <li><i>mm</i> is the minute within the hour ({@code 00} through
+     *     {@code 59}), as two decimal digits.
+     * <li><i>ss</i> is the second within the minute ({@code 00} through
+     *     {@code 61}), as two decimal digits.
+     * <li><i>GMT</i> is exactly the ASCII letters "{@code GMT}" to indicate
+     *     Greenwich Mean Time.
+     * </ul><p>
+     * The result does not depend on the local time zone.
+     *
+     * @return  a string representation of this date, using the Internet GMT
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toLocaleString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code DateFormat.format(Date date)}, using a
+     * GMT {@code TimeZone}.
+     */
+    @Deprecated
+    public String toGMTString() {
+        // d MMM yyyy HH:mm:ss 'GMT'
+        long t = getTime();
+        BaseCalendar cal = getCalendarSystem(t);
+        BaseCalendar.Date date =
+            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
+        StringBuilder sb = new StringBuilder(32);
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        sb.append(date.getYear()).append(' ');                            // yyyy
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
+        sb.append(" GMT");                                                // ' GMT'
+        return sb.toString();
+    }
+
+    /**
+     * Returns the offset, measured in minutes, for the local time zone
+     * relative to UTC that is appropriate for the time represented by
+     * this {@code Date} object.
+     * <p>
+     * For example, in Massachusetts, five time zones west of Greenwich:
+     * <blockquote><pre>
+     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
+     * because on February 14, 1996, standard time (Eastern Standard Time)
+     * is in use, which is offset five hours from UTC; but:
+     * <blockquote><pre>
+     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
+     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
+     * is in use, which is offset only four hours from UTC.<p>
+     * This method produces the same result as if it computed:
+     * <blockquote><pre>
+     * (this.getTime() - UTC(this.getYear(),
+     *                       this.getMonth(),
+     *                       this.getDate(),
+     *                       this.getHours(),
+     *                       this.getMinutes(),
+     *                       this.getSeconds())) / (60 * 1000)
+     * </pre></blockquote>
+     *
+     * @return  the time-zone offset, in minutes, for the current time zone.
+     * @see     java.util.Calendar#ZONE_OFFSET
+     * @see     java.util.Calendar#DST_OFFSET
+     * @see     java.util.TimeZone#getDefault
+     * @deprecated As of JDK version 1.1,
+     * replaced by {@code -(Calendar.get(Calendar.ZONE_OFFSET) +
+     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)}.
+     */
+    @Deprecated
+    public int getTimezoneOffset() {
+        int zoneOffset;
+        if (cdate == null) {
+            // Android-changed: Android specific time zone logic
+            GregorianCalendar cal = new GregorianCalendar(fastTime);
+            zoneOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
+        } else {
+            normalize();
+            zoneOffset = cdate.getZoneOffset();
+        }
+        return -zoneOffset/60000;  // convert to minutes
+    }
+
+    private final BaseCalendar.Date getCalendarDate() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+        }
+        return cdate;
+    }
+
+    private final BaseCalendar.Date normalize() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+            return cdate;
+        }
+
+        // Normalize cdate with the TimeZone in cdate first. This is
+        // required for the compatible behavior.
+        if (!cdate.isNormalized()) {
+            cdate = normalize(cdate);
+        }
+
+        // If the default TimeZone has changed, then recalculate the
+        // fields with the new TimeZone.
+        TimeZone tz = TimeZone.getDefaultRef();
+        if (tz != cdate.getZone()) {
+            cdate.setZone(tz);
+            CalendarSystem cal = getCalendarSystem(cdate);
+            cal.getCalendarDate(fastTime, cdate);
+        }
+        return cdate;
+    }
+
+    // fastTime and the returned data are in sync upon return.
+    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
+        int y = date.getNormalizedYear();
+        int m = date.getMonth();
+        int d = date.getDayOfMonth();
+        int hh = date.getHours();
+        int mm = date.getMinutes();
+        int ss = date.getSeconds();
+        int ms = date.getMillis();
+        TimeZone tz = date.getZone();
+
+        // If the specified year can't be handled using a long value
+        // in milliseconds, GregorianCalendar is used for full
+        // compatibility with underflow and overflow. This is required
+        // by some JCK tests. The limits are based max year values -
+        // years that can be represented by max values of d, hh, mm,
+        // ss and ms. Also, let GregorianCalendar handle the default
+        // cutover year so that we don't need to worry about the
+        // transition here.
+        if (y == 1582 || y > 280000000 || y < -280000000) {
+            if (tz == null) {
+                tz = TimeZone.getTimeZone("GMT");
+            }
+            GregorianCalendar gc = new GregorianCalendar(tz);
+            gc.clear();
+            gc.set(GregorianCalendar.MILLISECOND, ms);
+            gc.set(y, m-1, d, hh, mm, ss);
+            fastTime = gc.getTimeInMillis();
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
+            return date;
+        }
+
+        BaseCalendar cal = getCalendarSystem(y);
+        if (cal != getCalendarSystem(date)) {
+            date = (BaseCalendar.Date) cal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+        }
+        // Perform the GregorianCalendar-style normalization.
+        fastTime = cal.getTime(date);
+
+        // In case the normalized date requires the other calendar
+        // system, we need to recalculate it using the other one.
+        BaseCalendar ncal = getCalendarSystem(fastTime);
+        if (ncal != cal) {
+            date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+            fastTime = ncal.getTime(date);
+        }
+        return date;
+    }
+
+    /**
+     * Returns the Gregorian or Julian calendar system to use with the
+     * given date. Use Gregorian from October 15, 1582.
+     *
+     * @param year normalized calendar year (not -1900)
+     * @return the CalendarSystem to use for the specified date
+     */
+    private static final BaseCalendar getCalendarSystem(int year) {
+        if (year >= 1582) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(long utc) {
+        // Quickly check if the time stamp given by `utc' is the Epoch
+        // or later. If it's before 1970, we convert the cutover to
+        // local time to compare.
+        if (utc >= 0
+            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
+                        - TimeZone.getDefaultRef().getOffset(utc)) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
+        if (jcal == null) {
+            return gcal;
+        }
+        if (cdate.getEra() != null) {
+            return jcal;
+        }
+        return gcal;
+    }
+
+    private static final synchronized BaseCalendar getJulianCalendar() {
+        if (jcal == null) {
+            jcal = (BaseCalendar) CalendarSystem.forName("julian");
+        }
+        return jcal;
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData The value returned by {@code getTime()}
+     *             is emitted (long).  This represents the offset from
+     *             January 1, 1970, 00:00:00 GMT in milliseconds.
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream s)
+         throws IOException
+    {
+        s.defaultWriteObject();
+        s.writeLong(getTimeImpl());
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+        fastTime = s.readLong();
+    }
+
+    /**
+     * Obtains an instance of {@code Date} from an {@code Instant} object.
+     * <p>
+     * {@code Instant} uses a precision of nanoseconds, whereas {@code Date}
+     * uses a precision of milliseconds.  The conversion will truncate any
+     * excess precision information as though the amount in nanoseconds was
+     * subject to integer division by one million.
+     * <p>
+     * {@code Instant} can store points on the time-line further in the future
+     * and further in the past than {@code Date}. In this scenario, this method
+     * will throw an exception.
+     *
+     * @param instant  the instant to convert
+     * @return a {@code Date} representing the same point on the time-line as
+     *  the provided instant
+     * @throws    NullPointerException if {@code instant} is null.
+     * @throws    IllegalArgumentException if the instant is too large to
+     *  represent as a {@code Date}
+     * @since 1.8
+     */
+    public static Date from(Instant instant) {
+        try {
+            return new Date(instant.toEpochMilli());
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+    /**
+     * Converts this {@code Date} object to an {@code Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the same
+     * point on the time-line as this {@code Date}.
+     *
+     * @return an instant representing the same point on the time-line as
+     *  this {@code Date} object
+     * @since 1.8
+     */
+    public Instant toInstant() {
+        return Instant.ofEpochMilli(getTime());
+    }
+}
diff --git a/android-35/java/util/Deque.java b/android-35/java/util/Deque.java
new file mode 100644
index 0000000..0998f02
--- /dev/null
+++ b/android-35/java/util/Deque.java
@@ -0,0 +1,634 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea 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/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// Android-changed: removed link to collections framework docs
+/**
+ * A linear collection that supports element insertion and removal at
+ * both ends.  The name <i>deque</i> is short for "double ended queue"
+ * and is usually pronounced "deck".  Most {@code Deque}
+ * implementations place no fixed limits on the number of elements
+ * they may contain, but this interface supports capacity-restricted
+ * deques as well as those with no fixed size limit.
+ *
+ * <p>This interface defines methods to access the elements at both
+ * ends of the deque.  Methods are provided to insert, remove, and
+ * examine the element.  Each of these methods exists in two forms:
+ * one throws an exception if the operation fails, the other returns a
+ * special value (either {@code null} or {@code false}, depending on
+ * the operation).  The latter form of the insert operation is
+ * designed specifically for use with capacity-restricted
+ * {@code Deque} implementations; in most implementations, insert
+ * operations cannot fail.
+ *
+ * <p>The twelve methods described above are summarized in the
+ * following table:
+ *
+ * <table class="striped">
+ * <caption>Summary of Deque methods</caption>
+ *  <thead>
+ *  <tr>
+ *    <td rowspan="2"></td>
+ *    <th scope="col" colspan="2"> First Element (Head)</th>
+ *    <th scope="col" colspan="2"> Last Element (Tail)</th>
+ *  </tr>
+ *  <tr>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *    <th scope="row">Insert</th>
+ *    <td>{@link #addFirst(Object) addFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">Remove</th>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
+ *    <td>{@link #pollFirst() pollFirst()}</td>
+ *    <td>{@link #removeLast() removeLast()}</td>
+ *    <td>{@link #pollLast() pollLast()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">Examine</th>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *    <td>{@link #peekFirst() peekFirst()}</td>
+ *    <td>{@link #getLast() getLast()}</td>
+ *    <td>{@link #peekLast() peekLast()}</td>
+ *  </tr>
+ *  </tbody>
+ * </table>
+ *
+ * <p>This interface extends the {@link Queue} interface.  When a deque is
+ * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are
+ * added at the end of the deque and removed from the beginning.  The methods
+ * inherited from the {@code Queue} interface are precisely equivalent to
+ * {@code Deque} methods as indicated in the following table:
+ *
+ * <table class="striped">
+ * <caption>Comparison of Queue and Deque methods</caption>
+ *  <thead>
+ *  <tr>
+ *    <th scope="col"> {@code Queue} Method</th>
+ *    <th scope="col"> Equivalent {@code Deque} Method</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *    <th scope="row">{@link #add(Object) add(e)}</th>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #offer(Object) offer(e)}</th>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #remove() remove()}</th>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #poll() poll()}</th>
+ *    <td>{@link #pollFirst() pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #element() element()}</th>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #peek() peek()}</th>
+ *    <td>{@link #peekFirst() peekFirst()}</td>
+ *  </tr>
+ *  </tbody>
+ * </table>
+ *
+ * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This
+ * interface should be used in preference to the legacy {@link Stack} class.
+ * When a deque is used as a stack, elements are pushed and popped from the
+ * beginning of the deque.  Stack methods are equivalent to {@code Deque}
+ * methods as indicated in the table below:
+ *
+ * <table class="striped">
+ * <caption>Comparison of Stack and Deque methods</caption>
+ *  <thead>
+ *  <tr>
+ *    <th scope="col"> Stack Method</th>
+ *    <th scope="col"> Equivalent {@code Deque} Method</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *    <th scope="row">{@link #push(Object) push(e)}</th>
+ *    <td>{@link #addFirst(Object) addFirst(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #pop() pop()}</th>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">{@link #peek() peek()}</th>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  </tbody>
+ * </table>
+ *
+ * <p>Note that the {@link #peek peek} method works equally well when
+ * a deque is used as a queue or a stack; in either case, elements are
+ * drawn from the beginning of the deque.
+ *
+ * <p>This interface provides two methods to remove interior
+ * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and
+ * {@link #removeLastOccurrence removeLastOccurrence}.
+ *
+ * <p>Unlike the {@link List} interface, this interface does not
+ * provide support for indexed access to elements.
+ *
+ * <p>While {@code Deque} implementations are not strictly required
+ * to prohibit the insertion of null elements, they are strongly
+ * encouraged to do so.  Users of any {@code Deque} implementations
+ * that do allow null elements are strongly encouraged <i>not</i> to
+ * take advantage of the ability to insert nulls.  This is so because
+ * {@code null} is used as a special return value by various methods
+ * to indicate that the deque is empty.
+ *
+ * <p>{@code Deque} implementations generally do not define
+ * element-based versions of the {@code equals} and {@code hashCode}
+ * methods, but instead inherit the identity-based versions from class
+ * {@code Object}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @since  1.6
+ * @param <E> the type of elements held in this deque
+ */
+public interface Deque<E> extends Queue<E>, SequencedCollection<E> {
+    // Android-changed: fix framework docs link to "Collection#optional-restrictions"
+    // Several occurrences of the link have been fixed throughout.
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerLast}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addFirst} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addLast} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Retrieves and removes the first element of this deque.  This method
+     * differs from {@link #pollFirst pollFirst} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque.  This method
+     * differs from {@link #pollLast pollLast} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeLast();
+
+    /**
+     * Retrieves and removes the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E pollLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque.
+     *
+     * This method differs from {@link #peekFirst peekFirst} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque.
+     * This method differs from {@link #peekLast peekLast} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peekFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E peekLast();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} 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
+     *         ({@linkplain Collection##optional-restrictions optional})
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     *         ({@linkplain Collection##optional-restrictions optional})
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} 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
+     *         ({@linkplain Collection##optional-restrictions optional})
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     *         ({@linkplain Collection##optional-restrictions optional})
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * 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}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll() poll()} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the first element of this deque, or {@code null} if
+     *         this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst()}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    E peek();
+
+    /**
+     * Adds all of the elements in the specified collection at the end
+     * of this deque, as if by calling {@link #addLast} on each one,
+     * in the order that they are returned by the collection's iterator.
+     *
+     * <p>When using a capacity-restricted deque, it is generally preferable
+     * to call {@link #offer(Object) offer} separately on each element.
+     *
+     * <p>An exception encountered while trying to add an element may result
+     * in only some of the elements having been successfully added when
+     * the associated exception is thrown.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this deque
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this deque does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this deque
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void push(E e);
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E pop();
+
+
+    // *** Collection methods ***
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} 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
+     *         ({@linkplain Collection##optional-restrictions optional})
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     *         ({@linkplain Collection##optional-restrictions optional})
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     *         ({@linkplain Collection##optional-restrictions optional})
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     *         ({@linkplain Collection##optional-restrictions optional})
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * @return an iterator over the elements in this deque in reverse
+     * sequence
+     */
+    Iterator<E> descendingIterator();
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns a reverse-ordered Deque
+     * view. The {@code reversed()} method of the view returns a reference
+     * to this Deque. Other operations on the view are implemented via calls to
+     * public methods on this Deque. The exact relationship between calls on the
+     * view and calls on this Deque is unspecified. However, order-sensitive
+     * operations generally delegate to the appropriate method with the opposite
+     * orientation. For example, calling {@code getFirst} on the view results in
+     * a call to {@code getLast} on this Deque.
+     *
+     * @return a reverse-ordered view of this collection, as a {@code Deque}
+     * @since 21
+     */
+    default Deque<E> reversed() {
+        return ReverseOrderDequeView.of(this);
+    }
+}
diff --git a/android-35/java/util/Dictionary.java b/android-35/java/util/Dictionary.java
new file mode 100644
index 0000000..6538947
--- /dev/null
+++ b/android-35/java/util/Dictionary.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The {@code Dictionary} class is the abstract parent of any
+ * class, such as {@code Hashtable}, which maps keys to values.
+ * Every key and every value is an object. In any one {@code Dictionary}
+ * object, every key is associated with at most one value. Given a
+ * {@code Dictionary} and a key, the associated element can be looked up.
+ * Any non-{@code null} object can be used as a key and as a value.
+ * <p>
+ * As a rule, the {@code equals} method should be used by
+ * implementations of this class to decide if two keys are the same.
+ * <p>
+ * <strong>NOTE: This class is obsolete.  New implementations should
+ * implement the Map interface, rather than extending this class.</strong>
+ *
+ * @see     java.util.Map
+ * @see     java.lang.Object#equals(java.lang.Object)
+ * @see     java.lang.Object#hashCode()
+ * @see     java.util.Hashtable
+ * @since   1.0
+ */
+public abstract
+class Dictionary<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public Dictionary() {
+    }
+
+    /**
+     * Returns the number of entries (distinct keys) in this dictionary.
+     *
+     * @return  the number of keys in this dictionary.
+     */
+    public abstract int size();
+
+    /**
+     * Tests if this dictionary maps no keys to value. The general contract
+     * for the {@code isEmpty} method is that the result is true if and only
+     * if this dictionary contains no entries.
+     *
+     * @return  {@code true} if this dictionary maps no keys to values;
+     *          {@code false} otherwise.
+     */
+    public abstract boolean isEmpty();
+
+    /**
+     * Returns an enumeration of the keys in this dictionary. The general
+     * contract for the keys method is that an {@code Enumeration} object
+     * is returned that will generate all the keys for which this dictionary
+     * contains entries.
+     *
+     * @return  an enumeration of the keys in this dictionary.
+     * @see     java.util.Dictionary#elements()
+     * @see     java.util.Enumeration
+     */
+    public abstract Enumeration<K> keys();
+
+    /**
+     * Returns an enumeration of the values in this dictionary. The general
+     * contract for the {@code elements} method is that an
+     * {@code Enumeration} is returned that will generate all the elements
+     * contained in entries in this dictionary.
+     *
+     * @return  an enumeration of the values in this dictionary.
+     * @see     java.util.Dictionary#keys()
+     * @see     java.util.Enumeration
+     */
+    public abstract Enumeration<V> elements();
+
+    /**
+     * Returns the value to which the key is mapped in this dictionary.
+     * The general contract for the {@code isEmpty} method is that if this
+     * dictionary contains an entry for the specified key, the associated
+     * value is returned; otherwise, {@code null} is returned.
+     *
+     * @return  the value to which the key is mapped in this dictionary;
+     * @param   key   a key in this dictionary.
+     *          {@code null} if the key is not mapped to any value in
+     *          this dictionary.
+     * @throws    NullPointerException if the {@code key} is {@code null}.
+     * @see     java.util.Dictionary#put(java.lang.Object, java.lang.Object)
+     */
+    public abstract V get(Object key);
+
+    /**
+     * Maps the specified {@code key} to the specified
+     * {@code value} in this dictionary. Neither the key nor the
+     * value can be {@code null}.
+     * <p>
+     * If this dictionary already contains an entry for the specified
+     * {@code key}, the value already in this dictionary for that
+     * {@code key} is returned, after modifying the entry to contain the
+     *  new element. <p>If this dictionary does not already have an entry
+     *  for the specified {@code key}, an entry is created for the
+     *  specified {@code key} and {@code value}, and {@code null} is
+     *  returned.
+     * <p>
+     * The {@code value} can be retrieved by calling the
+     * {@code get} method with a {@code key} that is equal to
+     * the original {@code key}.
+     *
+     * @param      key     the hashtable key.
+     * @param      value   the value.
+     * @return     the previous value to which the {@code key} was mapped
+     *             in this dictionary, or {@code null} if the key did not
+     *             have a previous mapping.
+     * @throws     NullPointerException  if the {@code key} or
+     *               {@code value} is {@code null}.
+     * @see        java.lang.Object#equals(java.lang.Object)
+     * @see        java.util.Dictionary#get(java.lang.Object)
+     */
+    public abstract V put(K key, V value);
+
+    /**
+     * Removes the {@code key} (and its corresponding
+     * {@code value}) from this dictionary. This method does nothing
+     * if the {@code key} is not in this dictionary.
+     *
+     * @param   key   the key that needs to be removed.
+     * @return  the value to which the {@code key} had been mapped in this
+     *          dictionary, or {@code null} if the key did not have a
+     *          mapping.
+     * @throws    NullPointerException if {@code key} is {@code null}.
+     */
+    public abstract V remove(Object key);
+}
diff --git a/android-35/java/util/DoubleSummaryStatistics.java b/android-35/java/util/DoubleSummaryStatistics.java
new file mode 100644
index 0000000..06cd7aa
--- /dev/null
+++ b/android-35/java/util/DoubleSummaryStatistics.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.stream.Collector;
+import java.util.stream.DoubleStream;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of doubles with:
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new,
+ *                                                      DoubleSummaryStatistics::accept,
+ *                                                      DoubleSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code DoubleSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = people.stream()
+ *     .collect(Collectors.summarizingDouble(Person::getWeight));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their weights.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
+ * Collectors.summarizingDouble()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the count.
+ * @since 1.8
+ */
+public class DoubleSummaryStatistics implements DoubleConsumer {
+    private long count;
+    private double sum;
+    private double sumCompensation; // Low order bits of sum
+    private double simpleSum; // Used to compute right sum for non-finite inputs
+    private double min = Double.POSITIVE_INFINITY;
+    private double max = Double.NEGATIVE_INFINITY;
+
+    /**
+     * Constructs an empty instance with zero count, zero sum,
+     * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
+     * max and zero average.
+     */
+    public DoubleSummaryStatistics() { }
+
+    /**
+     * Constructs a non-empty instance with the specified {@code count},
+     * {@code min}, {@code max}, and {@code sum}.
+     *
+     * <p>If {@code count} is zero then the remaining arguments are ignored and
+     * an empty instance is constructed.
+     *
+     * <p>If the arguments are inconsistent then an {@code IllegalArgumentException}
+     * is thrown.  The necessary consistent argument conditions are:
+     * <ul>
+     *   <li>{@code count >= 0}</li>
+     *   <li>{@code (min <= max && !isNaN(sum)) || (isNaN(min) && isNaN(max) && isNaN(sum))}</li>
+     * </ul>
+     * @apiNote
+     * The enforcement of argument correctness means that the retrieved set of
+     * recorded values obtained from a {@code DoubleSummaryStatistics} source
+     * instance may not be a legal set of arguments for this constructor due to
+     * arithmetic overflow of the source's recorded count of values.
+     * The consistent argument conditions are not sufficient to prevent the
+     * creation of an internally inconsistent instance.  An example of such a
+     * state would be an instance with: {@code count} = 2, {@code min} = 1,
+     * {@code max} = 2, and {@code sum} = 0.
+     *
+     * @param count the count of values
+     * @param min the minimum value
+     * @param max the maximum value
+     * @param sum the sum of all values
+     * @throws IllegalArgumentException if the arguments are inconsistent
+     * @since 10
+     */
+    public DoubleSummaryStatistics(long count, double min, double max, double sum)
+            throws IllegalArgumentException {
+        if (count < 0L) {
+            throw new IllegalArgumentException("Negative count value");
+        } else if (count > 0L) {
+            if (min > max)
+                throw new IllegalArgumentException("Minimum greater than maximum");
+
+            // All NaN or non NaN
+            var ncount = DoubleStream.of(min, max, sum).filter(Double::isNaN).count();
+            if (ncount > 0 && ncount < 3)
+                throw new IllegalArgumentException("Some, not all, of the minimum, maximum, or sum is NaN");
+
+            this.count = count;
+            this.sum = sum;
+            this.simpleSum = sum;
+            this.sumCompensation = 0.0d;
+            this.min = min;
+            this.max = max;
+        }
+        // Use default field values if count == 0
+    }
+
+    /**
+     * Records another value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(double value) {
+        ++count;
+        simpleSum += value;
+        sumWithCompensation(value);
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code DoubleSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code DoubleSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(DoubleSummaryStatistics other) {
+        count += other.count;
+        simpleSum += other.simpleSum;
+        sumWithCompensation(other.sum);
+
+        // Subtract compensation bits
+        sumWithCompensation(-other.sumCompensation);
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensated summation.
+     */
+    private void sumWithCompensation(double value) {
+        double tmp = value - sumCompensation;
+        double velvel = sum + tmp; // Little wolf of rounding error
+        sumCompensation = (velvel - sum) - tmp;
+        sum = velvel;
+    }
+
+    /**
+     * Return the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * <p> The value of a floating-point sum is a function both of the
+     * input values as well as the order of addition operations. The
+     * order of addition operations of this method is intentionally
+     * not defined to allow for implementation flexibility to improve
+     * the speed and accuracy of the computed result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * Because of the unspecified order of operations and the
+     * possibility of using differing summation schemes, the output of
+     * this method may vary on the same input values.
+     *
+     * <p>Various conditions can result in a non-finite sum being
+     * computed. This can occur even if the all the recorded values
+     * being summed are finite. If any recorded value is non-finite,
+     * the sum will be non-finite:
+     *
+     * <ul>
+     *
+     * <li>If any recorded value is a NaN, then the final sum will be
+     * NaN.
+     *
+     * <li>If the recorded values contain one or more infinities, the
+     * sum will be infinite or NaN.
+     *
+     * <ul>
+     *
+     * <li>If the recorded values contain infinities of opposite sign,
+     * the sum will be NaN.
+     *
+     * <li>If the recorded values contain infinities of one sign and
+     * an intermediate sum overflows to an infinity of the opposite
+     * sign, the sum may be NaN.
+     *
+     * </ul>
+     *
+     * </ul>
+     *
+     * It is possible for intermediate sums of finite values to
+     * overflow into opposite-signed infinities; if that occurs, the
+     * final sum will be NaN even if the recorded values are all
+     * finite.
+     *
+     * If all the recorded values are zero, the sign of zero is
+     * <em>not</em> guaranteed to be preserved in the final sum.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final double getSum() {
+        // Better error bounds to add both terms as the final sum
+        double tmp =  sum - sumCompensation;
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            // If the compensated sum is spuriously NaN from
+            // accumulating one or more same-signed infinite values,
+            // return the correctly-signed infinity stored in
+            // simpleSum.
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no
+     * values have been recorded.
+     *
+     * <p> The computed average can vary numerically and have the
+     * special case behavior as computing the sum; see {@link #getSum}
+     * for details.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? getSum() / getCount() : 0.0d;
+    }
+
+    /**
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    @Override
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%f, min=%f, average=%f, max=%f}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/android-35/java/util/DualPivotQuicksort.java b/android-35/java/util/DualPivotQuicksort.java
new file mode 100644
index 0000000..ac96b34
--- /dev/null
+++ b/android-35/java/util/DualPivotQuicksort.java
@@ -0,0 +1,4161 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.RecursiveTask;
+
+/**
+ * This class implements powerful and fully optimized versions, both
+ * sequential and parallel, of the Dual-Pivot Quicksort algorithm by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * There are also additional algorithms, invoked from the Dual-Pivot
+ * Quicksort, such as mixed insertion sort, merging of runs and heap
+ * sort, counting sort and parallel merge sort.
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ * @author Doug Lea
+ *
+ * @version 2018.08.18
+ *
+ * @since 1.7 * 14
+ */
+final class DualPivotQuicksort {
+
+    /**
+     * Prevents instantiation.
+     */
+    private DualPivotQuicksort() {}
+
+    /**
+     * Max array size to use mixed insertion sort.
+     */
+    private static final int MAX_MIXED_INSERTION_SORT_SIZE = 65;
+
+    /**
+     * Max array size to use insertion sort.
+     */
+    private static final int MAX_INSERTION_SORT_SIZE = 44;
+
+    /**
+     * Min array size to perform sorting in parallel.
+     */
+    private static final int MIN_PARALLEL_SORT_SIZE = 4 << 10;
+
+    /**
+     * Min array size to try merging of runs.
+     */
+    private static final int MIN_TRY_MERGE_SIZE = 4 << 10;
+
+    /**
+     * Min size of the first run to continue with scanning.
+     */
+    private static final int MIN_FIRST_RUN_SIZE = 16;
+
+    /**
+     * Min factor for the first runs to continue scanning.
+     */
+    private static final int MIN_FIRST_RUNS_FACTOR = 7;
+
+    /**
+     * Max capacity of the index array for tracking runs.
+     */
+    private static final int MAX_RUN_CAPACITY = 5 << 10;
+
+    /**
+     * Min number of runs, required by parallel merging.
+     */
+    private static final int MIN_RUN_COUNT = 4;
+
+    /**
+     * Min array size to use parallel merging of parts.
+     */
+    private static final int MIN_PARALLEL_MERGE_PARTS_SIZE = 4 << 10;
+
+    /**
+     * Min size of a byte array to use counting sort.
+     */
+    private static final int MIN_BYTE_COUNTING_SORT_SIZE = 64;
+
+    /**
+     * Min size of a short or char array to use counting sort.
+     */
+    private static final int MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE = 1750;
+
+    /**
+     * Threshold of mixed insertion sort is incremented by this value.
+     */
+    private static final int DELTA = 3 << 1;
+
+    /**
+     * Max recursive partitioning depth before using heap sort.
+     */
+    private static final int MAX_RECURSION_DEPTH = 64 * DELTA;
+
+    /**
+     * Calculates the double depth of parallel merging.
+     * Depth is negative, if tasks split before sorting.
+     *
+     * @param parallelism the parallelism level
+     * @param size the target size
+     * @return the depth of parallel merging
+     */
+    private static int getDepth(int parallelism, int size) {
+        int depth = 0;
+
+        while ((parallelism >>= 3) > 0 && (size >>= 2) > 0) {
+            depth -= 2;
+        }
+        return depth;
+    }
+
+    /**
+     * Sorts the specified range of the array using parallel merge
+     * sort and/or Dual-Pivot Quicksort.
+     *
+     * To balance the faster splitting and parallelism of merge sort
+     * with the faster element partitioning of Quicksort, ranges are
+     * subdivided in tiers such that, if there is enough parallelism,
+     * the four-way parallel merge is started, still ensuring enough
+     * parallelism to process the partitions.
+     *
+     * @param a the array to be sorted
+     * @param parallelism the parallelism level
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(int[] a, int parallelism, int low, int high) {
+        int size = high - low;
+
+        if (parallelism > 1 && size > MIN_PARALLEL_SORT_SIZE) {
+            int depth = getDepth(parallelism, size >> 12);
+            int[] b = depth == 0 ? null : new int[size];
+            new Sorter(null, a, b, low, size, low, depth).invoke();
+        } else {
+            sort(null, a, 0, low, high);
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(Sorter sorter, int[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Run mixed insertion sort on small non-leftmost parts.
+             */
+            if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) {
+                mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high);
+                return;
+            }
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Check if the whole array or large non-leftmost
+             * parts are nearly sorted and then merge runs.
+             */
+            if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0)
+                    && tryMergeRuns(sorter, a, low, size)) {
+                return;
+            }
+
+            /*
+             * Switch to heap sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                heapSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            int a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { int t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { int t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { int t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                int pivot1 = a[e1];
+                int pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    int ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively (possibly in parallel),
+                 * excluding known pivots.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, lower + 1, upper);
+                    sorter.forkSorter(bits | 1, upper + 1, high);
+                } else {
+                    sort(sorter, a, bits | 1, lower + 1, upper);
+                    sort(sorter, a, bits | 1, upper + 1, high);
+                }
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                int pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    int ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part (possibly in parallel), excluding
+                 * known pivot. All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, upper, high);
+                } else {
+                    sort(sorter, a, bits | 1, upper, high);
+                }
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using mixed insertion sort.
+     *
+     * Mixed insertion sort is combination of simple insertion sort,
+     * pin insertion sort and pair insertion sort.
+     *
+     * In the context of Dual-Pivot Quicksort, the pivot element
+     * from the left part plays the role of sentinel, because it
+     * is less than any elements from the given part. Therefore,
+     * expensive check of the left range can be skipped on each
+     * iteration unless it is the leftmost call.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param end the index of the last element for simple insertion sort
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void mixedInsertionSort(int[] a, int low, int end, int high) {
+        if (end == high) {
+
+            /*
+             * Invoke simple insertion sort on tiny array.
+             */
+            for (int i; ++low < end; ) {
+                int ai = a[i = low];
+
+                while (ai < a[--i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        } else {
+
+            /*
+             * Start with pin insertion sort on small part.
+             *
+             * Pin insertion sort is extended simple insertion sort.
+             * The main idea of this sort is to put elements larger
+             * than an element called pin to the end of array (the
+             * proper area for such elements). It avoids expensive
+             * movements of these elements through the whole array.
+             */
+            int pin = a[end];
+
+            for (int i, p = high; ++low < end; ) {
+                int ai = a[i = low];
+
+                if (ai < a[i - 1]) { // Small element
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    a[i] = a[--i];
+
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+
+                } else if (p > i && ai > pin) { // Large element
+
+                    /*
+                     * Find element smaller than pin.
+                     */
+                    while (a[--p] > pin);
+
+                    /*
+                     * Swap it with large element.
+                     */
+                    if (p > i) {
+                        ai = a[p];
+                        a[p] = a[i];
+                    }
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+                }
+            }
+
+            /*
+             * Continue with pair insertion sort on remain part.
+             */
+            for (int i; low < high; ++low) {
+                int a1 = a[i = low], a2 = a[++low];
+
+                /*
+                 * Insert two elements per iteration: at first, insert the
+                 * larger element and then insert the smaller element, but
+                 * from the position where the larger element was inserted.
+                 */
+                if (a1 > a2) {
+
+                    while (a1 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a1;
+
+                    while (a2 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a2;
+
+                } else if (a1 < a[i - 1]) {
+
+                    while (a2 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a2;
+
+                    while (a1 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a1;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(int[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            int ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using heap sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void heapSort(int[] a, int low, int high) {
+        for (int k = (low + high) >>> 1; k > low; ) {
+            pushDown(a, --k, a[k], low, high);
+        }
+        while (--high > low) {
+            int max = a[low];
+            pushDown(a, low, a[high], low, high);
+            a[high] = max;
+        }
+    }
+
+    /**
+     * Pushes specified element down during heap sort.
+     *
+     * @param a the given array
+     * @param p the start index
+     * @param value the given element
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void pushDown(int[] a, int p, int value, int low, int high) {
+        for (int k ;; a[p] = a[p = k]) {
+            k = (p << 1) - low + 2; // Index of the right child
+
+            if (k > high) {
+                break;
+            }
+            if (k == high || a[k] < a[k - 1]) {
+                --k;
+            }
+            if (a[k] <= value) {
+                break;
+            }
+        }
+        a[p] = value;
+    }
+
+    /**
+     * Tries to sort the specified range of the array.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param low the index of the first element to be sorted
+     * @param size the array size
+     * @return true if finally sorted, false otherwise
+     */
+    private static boolean tryMergeRuns(Sorter sorter, int[] a, int low, int size) {
+
+        /*
+         * The run array is constructed only if initial runs are
+         * long enough to continue, run[i] then holds start index
+         * of the i-th sequence of elements in non-descending order.
+         */
+        int[] run = null;
+        int high = low + size;
+        int count = 1, last = low;
+
+        /*
+         * Identify all possible runs.
+         */
+        for (int k = low + 1; k < high; ) {
+
+            /*
+             * Find the end index of the current run.
+             */
+            if (a[k - 1] < a[k]) {
+
+                // Identify ascending sequence
+                while (++k < high && a[k - 1] <= a[k]);
+
+            } else if (a[k - 1] > a[k]) {
+
+                // Identify descending sequence
+                while (++k < high && a[k - 1] >= a[k]);
+
+                // Reverse into ascending order
+                for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+                    int ai = a[i]; a[i] = a[j]; a[j] = ai;
+                }
+            } else { // Identify constant sequence
+                for (int ak = a[k]; ++k < high && ak == a[k]; );
+
+                if (k < high) {
+                    continue;
+                }
+            }
+
+            /*
+             * Check special cases.
+             */
+            if (run == null) {
+                if (k == high) {
+
+                    /*
+                     * The array is monotonous sequence,
+                     * and therefore already sorted.
+                     */
+                    return true;
+                }
+
+                if (k - low < MIN_FIRST_RUN_SIZE) {
+
+                    /*
+                     * The first run is too small
+                     * to proceed with scanning.
+                     */
+                    return false;
+                }
+
+                run = new int[((size >> 10) | 0x7F) & 0x3FF];
+                run[0] = low;
+
+            } else if (a[last - 1] > a[last]) {
+
+                if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) {
+
+                    /*
+                     * The first runs are not long
+                     * enough to continue scanning.
+                     */
+                    return false;
+                }
+
+                if (++count == MAX_RUN_CAPACITY) {
+
+                    /*
+                     * Array is not highly structured.
+                     */
+                    return false;
+                }
+
+                if (count == run.length) {
+
+                    /*
+                     * Increase capacity of index array.
+                     */
+                    run = Arrays.copyOf(run, count << 1);
+                }
+            }
+            run[count] = (last = k);
+        }
+
+        /*
+         * Merge runs of highly structured array.
+         */
+        if (count > 1) {
+            int[] b; int offset = low;
+
+            if (sorter == null || (b = (int[]) sorter.b) == null) {
+                b = new int[size];
+            } else {
+                offset = sorter.offset;
+            }
+            mergeRuns(a, b, offset, 1, sorter != null, run, 0, count);
+        }
+        return true;
+    }
+
+    /**
+     * Merges the specified runs.
+     *
+     * @param a the source array
+     * @param b the temporary buffer used in merging
+     * @param offset the start index in the source, inclusive
+     * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0)
+     * @param parallel indicates whether merging is performed in parallel
+     * @param run the start indexes of the runs, inclusive
+     * @param lo the start index of the first run, inclusive
+     * @param hi the start index of the last run, inclusive
+     * @return the destination where runs are merged
+     */
+    private static int[] mergeRuns(int[] a, int[] b, int offset,
+            int aim, boolean parallel, int[] run, int lo, int hi) {
+
+        if (hi - lo == 1) {
+            if (aim >= 0) {
+                return a;
+            }
+            for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+                b[--j] = a[--i]
+            );
+            return b;
+        }
+
+        /*
+         * Split into approximately equal parts.
+         */
+        int mi = lo, rmi = (run[lo] + run[hi]) >>> 1;
+        while (run[++mi + 1] <= rmi);
+
+        /*
+         * Merge the left and right parts.
+         */
+        int[] a1, a2;
+
+        if (parallel && hi - lo > MIN_RUN_COUNT) {
+            RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe();
+            a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi);
+            a2 = (int[]) merger.getDestination();
+        } else {
+            a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi);
+            a2 = mergeRuns(a, b, offset,    0, false, run, mi, hi);
+        }
+
+        int[] dst = a1 == a ? b : a;
+
+        int k   = a1 == a ? run[lo] - offset : run[lo];
+        int lo1 = a1 == b ? run[lo] - offset : run[lo];
+        int hi1 = a1 == b ? run[mi] - offset : run[mi];
+        int lo2 = a2 == b ? run[mi] - offset : run[mi];
+        int hi2 = a2 == b ? run[hi] - offset : run[hi];
+
+        if (parallel) {
+            new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke();
+        } else {
+            mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2);
+        }
+        return dst;
+    }
+
+    /**
+     * Merges the sorted parts.
+     *
+     * @param merger parallel context
+     * @param dst the destination where parts are merged
+     * @param k the start index of the destination, inclusive
+     * @param a1 the first part
+     * @param lo1 the start index of the first part, inclusive
+     * @param hi1 the end index of the first part, exclusive
+     * @param a2 the second part
+     * @param lo2 the start index of the second part, inclusive
+     * @param hi2 the end index of the second part, exclusive
+     */
+    private static void mergeParts(Merger merger, int[] dst, int k,
+            int[] a1, int lo1, int hi1, int[] a2, int lo2, int hi2) {
+
+        if (merger != null && a1 == a2) {
+
+            while (true) {
+
+                /*
+                 * The first part must be larger.
+                 */
+                if (hi1 - lo1 < hi2 - lo2) {
+                    int lo = lo1; lo1 = lo2; lo2 = lo;
+                    int hi = hi1; hi1 = hi2; hi2 = hi;
+                }
+
+                /*
+                 * Small parts will be merged sequentially.
+                 */
+                if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) {
+                    break;
+                }
+
+                /*
+                 * Find the median of the larger part.
+                 */
+                int mi1 = (lo1 + hi1) >>> 1;
+                int key = a1[mi1];
+                int mi2 = hi2;
+
+                /*
+                 * Partition the smaller part.
+                 */
+                for (int loo = lo2; loo < mi2; ) {
+                    int t = (loo + mi2) >>> 1;
+
+                    if (key > a2[t]) {
+                        loo = t + 1;
+                    } else {
+                        mi2 = t;
+                    }
+                }
+
+                int d = mi2 - lo2 + mi1 - lo1;
+
+                /*
+                 * Merge the right sub-parts in parallel.
+                 */
+                merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2);
+
+                /*
+                 * Process the sub-left parts.
+                 */
+                hi1 = mi1;
+                hi2 = mi2;
+            }
+        }
+
+        /*
+         * Merge small parts sequentially.
+         */
+        while (lo1 < hi1 && lo2 < hi2) {
+            dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++];
+        }
+        if (dst != a1 || k < lo1) {
+            while (lo1 < hi1) {
+                dst[k++] = a1[lo1++];
+            }
+        }
+        if (dst != a2 || k < lo2) {
+            while (lo2 < hi2) {
+                dst[k++] = a2[lo2++];
+            }
+        }
+    }
+
+// [long]
+
+    /**
+     * Sorts the specified range of the array using parallel merge
+     * sort and/or Dual-Pivot Quicksort.
+     *
+     * To balance the faster splitting and parallelism of merge sort
+     * with the faster element partitioning of Quicksort, ranges are
+     * subdivided in tiers such that, if there is enough parallelism,
+     * the four-way parallel merge is started, still ensuring enough
+     * parallelism to process the partitions.
+     *
+     * @param a the array to be sorted
+     * @param parallelism the parallelism level
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(long[] a, int parallelism, int low, int high) {
+        int size = high - low;
+
+        if (parallelism > 1 && size > MIN_PARALLEL_SORT_SIZE) {
+            int depth = getDepth(parallelism, size >> 12);
+            long[] b = depth == 0 ? null : new long[size];
+            new Sorter(null, a, b, low, size, low, depth).invoke();
+        } else {
+            sort(null, a, 0, low, high);
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(Sorter sorter, long[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Run mixed insertion sort on small non-leftmost parts.
+             */
+            if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) {
+                mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high);
+                return;
+            }
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Check if the whole array or large non-leftmost
+             * parts are nearly sorted and then merge runs.
+             */
+            if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0)
+                    && tryMergeRuns(sorter, a, low, size)) {
+                return;
+            }
+
+            /*
+             * Switch to heap sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                heapSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            long a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { long t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { long t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { long t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                long pivot1 = a[e1];
+                long pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    long ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively (possibly in parallel),
+                 * excluding known pivots.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, lower + 1, upper);
+                    sorter.forkSorter(bits | 1, upper + 1, high);
+                } else {
+                    sort(sorter, a, bits | 1, lower + 1, upper);
+                    sort(sorter, a, bits | 1, upper + 1, high);
+                }
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                long pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    long ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part (possibly in parallel), excluding
+                 * known pivot. All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, upper, high);
+                } else {
+                    sort(sorter, a, bits | 1, upper, high);
+                }
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using mixed insertion sort.
+     *
+     * Mixed insertion sort is combination of simple insertion sort,
+     * pin insertion sort and pair insertion sort.
+     *
+     * In the context of Dual-Pivot Quicksort, the pivot element
+     * from the left part plays the role of sentinel, because it
+     * is less than any elements from the given part. Therefore,
+     * expensive check of the left range can be skipped on each
+     * iteration unless it is the leftmost call.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param end the index of the last element for simple insertion sort
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void mixedInsertionSort(long[] a, int low, int end, int high) {
+        if (end == high) {
+
+            /*
+             * Invoke simple insertion sort on tiny array.
+             */
+            for (int i; ++low < end; ) {
+                long ai = a[i = low];
+
+                while (ai < a[--i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        } else {
+
+            /*
+             * Start with pin insertion sort on small part.
+             *
+             * Pin insertion sort is extended simple insertion sort.
+             * The main idea of this sort is to put elements larger
+             * than an element called pin to the end of array (the
+             * proper area for such elements). It avoids expensive
+             * movements of these elements through the whole array.
+             */
+            long pin = a[end];
+
+            for (int i, p = high; ++low < end; ) {
+                long ai = a[i = low];
+
+                if (ai < a[i - 1]) { // Small element
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    a[i] = a[--i];
+
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+
+                } else if (p > i && ai > pin) { // Large element
+
+                    /*
+                     * Find element smaller than pin.
+                     */
+                    while (a[--p] > pin);
+
+                    /*
+                     * Swap it with large element.
+                     */
+                    if (p > i) {
+                        ai = a[p];
+                        a[p] = a[i];
+                    }
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+                }
+            }
+
+            /*
+             * Continue with pair insertion sort on remain part.
+             */
+            for (int i; low < high; ++low) {
+                long a1 = a[i = low], a2 = a[++low];
+
+                /*
+                 * Insert two elements per iteration: at first, insert the
+                 * larger element and then insert the smaller element, but
+                 * from the position where the larger element was inserted.
+                 */
+                if (a1 > a2) {
+
+                    while (a1 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a1;
+
+                    while (a2 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a2;
+
+                } else if (a1 < a[i - 1]) {
+
+                    while (a2 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a2;
+
+                    while (a1 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a1;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(long[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            long ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using heap sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void heapSort(long[] a, int low, int high) {
+        for (int k = (low + high) >>> 1; k > low; ) {
+            pushDown(a, --k, a[k], low, high);
+        }
+        while (--high > low) {
+            long max = a[low];
+            pushDown(a, low, a[high], low, high);
+            a[high] = max;
+        }
+    }
+
+    /**
+     * Pushes specified element down during heap sort.
+     *
+     * @param a the given array
+     * @param p the start index
+     * @param value the given element
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void pushDown(long[] a, int p, long value, int low, int high) {
+        for (int k ;; a[p] = a[p = k]) {
+            k = (p << 1) - low + 2; // Index of the right child
+
+            if (k > high) {
+                break;
+            }
+            if (k == high || a[k] < a[k - 1]) {
+                --k;
+            }
+            if (a[k] <= value) {
+                break;
+            }
+        }
+        a[p] = value;
+    }
+
+    /**
+     * Tries to sort the specified range of the array.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param low the index of the first element to be sorted
+     * @param size the array size
+     * @return true if finally sorted, false otherwise
+     */
+    private static boolean tryMergeRuns(Sorter sorter, long[] a, int low, int size) {
+
+        /*
+         * The run array is constructed only if initial runs are
+         * long enough to continue, run[i] then holds start index
+         * of the i-th sequence of elements in non-descending order.
+         */
+        int[] run = null;
+        int high = low + size;
+        int count = 1, last = low;
+
+        /*
+         * Identify all possible runs.
+         */
+        for (int k = low + 1; k < high; ) {
+
+            /*
+             * Find the end index of the current run.
+             */
+            if (a[k - 1] < a[k]) {
+
+                // Identify ascending sequence
+                while (++k < high && a[k - 1] <= a[k]);
+
+            } else if (a[k - 1] > a[k]) {
+
+                // Identify descending sequence
+                while (++k < high && a[k - 1] >= a[k]);
+
+                // Reverse into ascending order
+                for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+                    long ai = a[i]; a[i] = a[j]; a[j] = ai;
+                }
+            } else { // Identify constant sequence
+                for (long ak = a[k]; ++k < high && ak == a[k]; );
+
+                if (k < high) {
+                    continue;
+                }
+            }
+
+            /*
+             * Check special cases.
+             */
+            if (run == null) {
+                if (k == high) {
+
+                    /*
+                     * The array is monotonous sequence,
+                     * and therefore already sorted.
+                     */
+                    return true;
+                }
+
+                if (k - low < MIN_FIRST_RUN_SIZE) {
+
+                    /*
+                     * The first run is too small
+                     * to proceed with scanning.
+                     */
+                    return false;
+                }
+
+                run = new int[((size >> 10) | 0x7F) & 0x3FF];
+                run[0] = low;
+
+            } else if (a[last - 1] > a[last]) {
+
+                if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) {
+
+                    /*
+                     * The first runs are not long
+                     * enough to continue scanning.
+                     */
+                    return false;
+                }
+
+                if (++count == MAX_RUN_CAPACITY) {
+
+                    /*
+                     * Array is not highly structured.
+                     */
+                    return false;
+                }
+
+                if (count == run.length) {
+
+                    /*
+                     * Increase capacity of index array.
+                     */
+                    run = Arrays.copyOf(run, count << 1);
+                }
+            }
+            run[count] = (last = k);
+        }
+
+        /*
+         * Merge runs of highly structured array.
+         */
+        if (count > 1) {
+            long[] b; int offset = low;
+
+            if (sorter == null || (b = (long[]) sorter.b) == null) {
+                b = new long[size];
+            } else {
+                offset = sorter.offset;
+            }
+            mergeRuns(a, b, offset, 1, sorter != null, run, 0, count);
+        }
+        return true;
+    }
+
+    /**
+     * Merges the specified runs.
+     *
+     * @param a the source array
+     * @param b the temporary buffer used in merging
+     * @param offset the start index in the source, inclusive
+     * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0)
+     * @param parallel indicates whether merging is performed in parallel
+     * @param run the start indexes of the runs, inclusive
+     * @param lo the start index of the first run, inclusive
+     * @param hi the start index of the last run, inclusive
+     * @return the destination where runs are merged
+     */
+    private static long[] mergeRuns(long[] a, long[] b, int offset,
+            int aim, boolean parallel, int[] run, int lo, int hi) {
+
+        if (hi - lo == 1) {
+            if (aim >= 0) {
+                return a;
+            }
+            for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+                b[--j] = a[--i]
+            );
+            return b;
+        }
+
+        /*
+         * Split into approximately equal parts.
+         */
+        int mi = lo, rmi = (run[lo] + run[hi]) >>> 1;
+        while (run[++mi + 1] <= rmi);
+
+        /*
+         * Merge the left and right parts.
+         */
+        long[] a1, a2;
+
+        if (parallel && hi - lo > MIN_RUN_COUNT) {
+            RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe();
+            a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi);
+            a2 = (long[]) merger.getDestination();
+        } else {
+            a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi);
+            a2 = mergeRuns(a, b, offset,    0, false, run, mi, hi);
+        }
+
+        long[] dst = a1 == a ? b : a;
+
+        int k   = a1 == a ? run[lo] - offset : run[lo];
+        int lo1 = a1 == b ? run[lo] - offset : run[lo];
+        int hi1 = a1 == b ? run[mi] - offset : run[mi];
+        int lo2 = a2 == b ? run[mi] - offset : run[mi];
+        int hi2 = a2 == b ? run[hi] - offset : run[hi];
+
+        if (parallel) {
+            new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke();
+        } else {
+            mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2);
+        }
+        return dst;
+    }
+
+    /**
+     * Merges the sorted parts.
+     *
+     * @param merger parallel context
+     * @param dst the destination where parts are merged
+     * @param k the start index of the destination, inclusive
+     * @param a1 the first part
+     * @param lo1 the start index of the first part, inclusive
+     * @param hi1 the end index of the first part, exclusive
+     * @param a2 the second part
+     * @param lo2 the start index of the second part, inclusive
+     * @param hi2 the end index of the second part, exclusive
+     */
+    private static void mergeParts(Merger merger, long[] dst, int k,
+            long[] a1, int lo1, int hi1, long[] a2, int lo2, int hi2) {
+
+        if (merger != null && a1 == a2) {
+
+            while (true) {
+
+                /*
+                 * The first part must be larger.
+                 */
+                if (hi1 - lo1 < hi2 - lo2) {
+                    int lo = lo1; lo1 = lo2; lo2 = lo;
+                    int hi = hi1; hi1 = hi2; hi2 = hi;
+                }
+
+                /*
+                 * Small parts will be merged sequentially.
+                 */
+                if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) {
+                    break;
+                }
+
+                /*
+                 * Find the median of the larger part.
+                 */
+                int mi1 = (lo1 + hi1) >>> 1;
+                long key = a1[mi1];
+                int mi2 = hi2;
+
+                /*
+                 * Partition the smaller part.
+                 */
+                for (int loo = lo2; loo < mi2; ) {
+                    int t = (loo + mi2) >>> 1;
+
+                    if (key > a2[t]) {
+                        loo = t + 1;
+                    } else {
+                        mi2 = t;
+                    }
+                }
+
+                int d = mi2 - lo2 + mi1 - lo1;
+
+                /*
+                 * Merge the right sub-parts in parallel.
+                 */
+                merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2);
+
+                /*
+                 * Process the sub-left parts.
+                 */
+                hi1 = mi1;
+                hi2 = mi2;
+            }
+        }
+
+        /*
+         * Merge small parts sequentially.
+         */
+        while (lo1 < hi1 && lo2 < hi2) {
+            dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++];
+        }
+        if (dst != a1 || k < lo1) {
+            while (lo1 < hi1) {
+                dst[k++] = a1[lo1++];
+            }
+        }
+        if (dst != a2 || k < lo2) {
+            while (lo2 < hi2) {
+                dst[k++] = a2[lo2++];
+            }
+        }
+    }
+
+// [byte]
+
+    /**
+     * Sorts the specified range of the array using
+     * counting sort or insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(byte[] a, int low, int high) {
+        if (high - low > MIN_BYTE_COUNTING_SORT_SIZE) {
+            countingSort(a, low, high);
+        } else {
+            insertionSort(a, low, high);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(byte[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            byte ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * The number of distinct byte values.
+     */
+    private static final int NUM_BYTE_VALUES = 1 << 8;
+
+    /**
+     * Max index of byte counter.
+     */
+    private static final int MAX_BYTE_INDEX = Byte.MAX_VALUE + NUM_BYTE_VALUES + 1;
+
+    /**
+     * Sorts the specified range of the array using counting sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void countingSort(byte[] a, int low, int high) {
+        int[] count = new int[NUM_BYTE_VALUES];
+
+        /*
+         * Compute a histogram with the number of each values.
+         */
+        for (int i = high; i > low; ++count[a[--i] & 0xFF]);
+
+        /*
+         * Place values on their final positions.
+         */
+        if (high - low > NUM_BYTE_VALUES) {
+            for (int i = MAX_BYTE_INDEX; --i > Byte.MAX_VALUE; ) {
+                int value = i & 0xFF;
+
+                for (low = high - count[value]; high > low;
+                    a[--high] = (byte) value
+                );
+            }
+        } else {
+            for (int i = MAX_BYTE_INDEX; high > low; ) {
+                while (count[--i & 0xFF] == 0);
+
+                int value = i & 0xFF;
+                int c = count[value];
+
+                do {
+                    a[--high] = (byte) value;
+                } while (--c > 0);
+            }
+        }
+    }
+
+// [char]
+
+    /**
+     * Sorts the specified range of the array using
+     * counting sort or Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(char[] a, int low, int high) {
+        if (high - low > MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE) {
+            countingSort(a, low, high);
+        } else {
+            sort(a, 0, low, high);
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(char[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Switch to counting sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                countingSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            char a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { char t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { char t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { char t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                char pivot1 = a[e1];
+                char pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    char ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively,
+                 * excluding known pivots.
+                 */
+                sort(a, bits | 1, lower + 1, upper);
+                sort(a, bits | 1, upper + 1, high);
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                char pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    char ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part, excluding known pivot.
+                 * All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                sort(a, bits | 1, upper, high);
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(char[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            char ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * The number of distinct char values.
+     */
+    private static final int NUM_CHAR_VALUES = 1 << 16;
+
+    /**
+     * Sorts the specified range of the array using counting sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void countingSort(char[] a, int low, int high) {
+        int[] count = new int[NUM_CHAR_VALUES];
+
+        /*
+         * Compute a histogram with the number of each values.
+         */
+        for (int i = high; i > low; ++count[a[--i]]);
+
+        /*
+         * Place values on their final positions.
+         */
+        if (high - low > NUM_CHAR_VALUES) {
+            for (int i = NUM_CHAR_VALUES; i > 0; ) {
+                for (low = high - count[--i]; high > low;
+                    a[--high] = (char) i
+                );
+            }
+        } else {
+            for (int i = NUM_CHAR_VALUES; high > low; ) {
+                while (count[--i] == 0);
+                int c = count[i];
+
+                do {
+                    a[--high] = (char) i;
+                } while (--c > 0);
+            }
+        }
+    }
+
+// [short]
+
+    /**
+     * Sorts the specified range of the array using
+     * counting sort or Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(short[] a, int low, int high) {
+        if (high - low > MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE) {
+            countingSort(a, low, high);
+        } else {
+            sort(a, 0, low, high);
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(short[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Switch to counting sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                countingSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            short a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { short t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { short t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { short t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                short pivot1 = a[e1];
+                short pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    short ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively,
+                 * excluding known pivots.
+                 */
+                sort(a, bits | 1, lower + 1, upper);
+                sort(a, bits | 1, upper + 1, high);
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                short pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    short ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part, excluding known pivot.
+                 * All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                sort(a, bits | 1, upper, high);
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(short[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            short ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * The number of distinct short values.
+     */
+    private static final int NUM_SHORT_VALUES = 1 << 16;
+
+    /**
+     * Max index of short counter.
+     */
+    private static final int MAX_SHORT_INDEX = Short.MAX_VALUE + NUM_SHORT_VALUES + 1;
+
+    /**
+     * Sorts the specified range of the array using counting sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void countingSort(short[] a, int low, int high) {
+        int[] count = new int[NUM_SHORT_VALUES];
+
+        /*
+         * Compute a histogram with the number of each values.
+         */
+        for (int i = high; i > low; ++count[a[--i] & 0xFFFF]);
+
+        /*
+         * Place values on their final positions.
+         */
+        if (high - low > NUM_SHORT_VALUES) {
+            for (int i = MAX_SHORT_INDEX; --i > Short.MAX_VALUE; ) {
+                int value = i & 0xFFFF;
+
+                for (low = high - count[value]; high > low;
+                    a[--high] = (short) value
+                );
+            }
+        } else {
+            for (int i = MAX_SHORT_INDEX; high > low; ) {
+                while (count[--i & 0xFFFF] == 0);
+
+                int value = i & 0xFFFF;
+                int c = count[value];
+
+                do {
+                    a[--high] = (short) value;
+                } while (--c > 0);
+            }
+        }
+    }
+
+// [float]
+
+    /**
+     * Sorts the specified range of the array using parallel merge
+     * sort and/or Dual-Pivot Quicksort.
+     *
+     * To balance the faster splitting and parallelism of merge sort
+     * with the faster element partitioning of Quicksort, ranges are
+     * subdivided in tiers such that, if there is enough parallelism,
+     * the four-way parallel merge is started, still ensuring enough
+     * parallelism to process the partitions.
+     *
+     * @param a the array to be sorted
+     * @param parallelism the parallelism level
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(float[] a, int parallelism, int low, int high) {
+        /*
+         * Phase 1. Count the number of negative zero -0.0f,
+         * turn them into positive zero, and move all NaNs
+         * to the end of the array.
+         */
+        int numNegativeZero = 0;
+
+        for (int k = high; k > low; ) {
+            float ak = a[--k];
+
+            if (ak == 0.0f && Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f
+                numNegativeZero += 1;
+                a[k] = 0.0f;
+            } else if (ak != ak) { // ak is NaN
+                a[k] = a[--high];
+                a[high] = ak;
+            }
+        }
+
+        /*
+         * Phase 2. Sort everything except NaNs,
+         * which are already in place.
+         */
+        int size = high - low;
+
+        if (parallelism > 1 && size > MIN_PARALLEL_SORT_SIZE) {
+            int depth = getDepth(parallelism, size >> 12);
+            float[] b = depth == 0 ? null : new float[size];
+            new Sorter(null, a, b, low, size, low, depth).invoke();
+        } else {
+            sort(null, a, 0, low, high);
+        }
+
+        /*
+         * Phase 3. Turn positive zero 0.0f
+         * back into negative zero -0.0f.
+         */
+        if (++numNegativeZero == 1) {
+            return;
+        }
+
+        /*
+         * Find the position one less than
+         * the index of the first zero.
+         */
+        while (low <= high) {
+            int middle = (low + high) >>> 1;
+
+            if (a[middle] < 0) {
+                low = middle + 1;
+            } else {
+                high = middle - 1;
+            }
+        }
+
+        /*
+         * Replace the required number of 0.0f by -0.0f.
+         */
+        while (--numNegativeZero > 0) {
+            a[++high] = -0.0f;
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(Sorter sorter, float[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Run mixed insertion sort on small non-leftmost parts.
+             */
+            if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) {
+                mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high);
+                return;
+            }
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Check if the whole array or large non-leftmost
+             * parts are nearly sorted and then merge runs.
+             */
+            if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0)
+                    && tryMergeRuns(sorter, a, low, size)) {
+                return;
+            }
+
+            /*
+             * Switch to heap sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                heapSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            float a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { float t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { float t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { float t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                float pivot1 = a[e1];
+                float pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    float ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively (possibly in parallel),
+                 * excluding known pivots.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, lower + 1, upper);
+                    sorter.forkSorter(bits | 1, upper + 1, high);
+                } else {
+                    sort(sorter, a, bits | 1, lower + 1, upper);
+                    sort(sorter, a, bits | 1, upper + 1, high);
+                }
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                float pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    float ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part (possibly in parallel), excluding
+                 * known pivot. All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, upper, high);
+                } else {
+                    sort(sorter, a, bits | 1, upper, high);
+                }
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using mixed insertion sort.
+     *
+     * Mixed insertion sort is combination of simple insertion sort,
+     * pin insertion sort and pair insertion sort.
+     *
+     * In the context of Dual-Pivot Quicksort, the pivot element
+     * from the left part plays the role of sentinel, because it
+     * is less than any elements from the given part. Therefore,
+     * expensive check of the left range can be skipped on each
+     * iteration unless it is the leftmost call.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param end the index of the last element for simple insertion sort
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void mixedInsertionSort(float[] a, int low, int end, int high) {
+        if (end == high) {
+
+            /*
+             * Invoke simple insertion sort on tiny array.
+             */
+            for (int i; ++low < end; ) {
+                float ai = a[i = low];
+
+                while (ai < a[--i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        } else {
+
+            /*
+             * Start with pin insertion sort on small part.
+             *
+             * Pin insertion sort is extended simple insertion sort.
+             * The main idea of this sort is to put elements larger
+             * than an element called pin to the end of array (the
+             * proper area for such elements). It avoids expensive
+             * movements of these elements through the whole array.
+             */
+            float pin = a[end];
+
+            for (int i, p = high; ++low < end; ) {
+                float ai = a[i = low];
+
+                if (ai < a[i - 1]) { // Small element
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    a[i] = a[--i];
+
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+
+                } else if (p > i && ai > pin) { // Large element
+
+                    /*
+                     * Find element smaller than pin.
+                     */
+                    while (a[--p] > pin);
+
+                    /*
+                     * Swap it with large element.
+                     */
+                    if (p > i) {
+                        ai = a[p];
+                        a[p] = a[i];
+                    }
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+                }
+            }
+
+            /*
+             * Continue with pair insertion sort on remain part.
+             */
+            for (int i; low < high; ++low) {
+                float a1 = a[i = low], a2 = a[++low];
+
+                /*
+                 * Insert two elements per iteration: at first, insert the
+                 * larger element and then insert the smaller element, but
+                 * from the position where the larger element was inserted.
+                 */
+                if (a1 > a2) {
+
+                    while (a1 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a1;
+
+                    while (a2 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a2;
+
+                } else if (a1 < a[i - 1]) {
+
+                    while (a2 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a2;
+
+                    while (a1 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a1;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(float[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            float ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using heap sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void heapSort(float[] a, int low, int high) {
+        for (int k = (low + high) >>> 1; k > low; ) {
+            pushDown(a, --k, a[k], low, high);
+        }
+        while (--high > low) {
+            float max = a[low];
+            pushDown(a, low, a[high], low, high);
+            a[high] = max;
+        }
+    }
+
+    /**
+     * Pushes specified element down during heap sort.
+     *
+     * @param a the given array
+     * @param p the start index
+     * @param value the given element
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void pushDown(float[] a, int p, float value, int low, int high) {
+        for (int k ;; a[p] = a[p = k]) {
+            k = (p << 1) - low + 2; // Index of the right child
+
+            if (k > high) {
+                break;
+            }
+            if (k == high || a[k] < a[k - 1]) {
+                --k;
+            }
+            if (a[k] <= value) {
+                break;
+            }
+        }
+        a[p] = value;
+    }
+
+    /**
+     * Tries to sort the specified range of the array.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param low the index of the first element to be sorted
+     * @param size the array size
+     * @return true if finally sorted, false otherwise
+     */
+    private static boolean tryMergeRuns(Sorter sorter, float[] a, int low, int size) {
+
+        /*
+         * The run array is constructed only if initial runs are
+         * long enough to continue, run[i] then holds start index
+         * of the i-th sequence of elements in non-descending order.
+         */
+        int[] run = null;
+        int high = low + size;
+        int count = 1, last = low;
+
+        /*
+         * Identify all possible runs.
+         */
+        for (int k = low + 1; k < high; ) {
+
+            /*
+             * Find the end index of the current run.
+             */
+            if (a[k - 1] < a[k]) {
+
+                // Identify ascending sequence
+                while (++k < high && a[k - 1] <= a[k]);
+
+            } else if (a[k - 1] > a[k]) {
+
+                // Identify descending sequence
+                while (++k < high && a[k - 1] >= a[k]);
+
+                // Reverse into ascending order
+                for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+                    float ai = a[i]; a[i] = a[j]; a[j] = ai;
+                }
+            } else { // Identify constant sequence
+                for (float ak = a[k]; ++k < high && ak == a[k]; );
+
+                if (k < high) {
+                    continue;
+                }
+            }
+
+            /*
+             * Check special cases.
+             */
+            if (run == null) {
+                if (k == high) {
+
+                    /*
+                     * The array is monotonous sequence,
+                     * and therefore already sorted.
+                     */
+                    return true;
+                }
+
+                if (k - low < MIN_FIRST_RUN_SIZE) {
+
+                    /*
+                     * The first run is too small
+                     * to proceed with scanning.
+                     */
+                    return false;
+                }
+
+                run = new int[((size >> 10) | 0x7F) & 0x3FF];
+                run[0] = low;
+
+            } else if (a[last - 1] > a[last]) {
+
+                if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) {
+
+                    /*
+                     * The first runs are not long
+                     * enough to continue scanning.
+                     */
+                    return false;
+                }
+
+                if (++count == MAX_RUN_CAPACITY) {
+
+                    /*
+                     * Array is not highly structured.
+                     */
+                    return false;
+                }
+
+                if (count == run.length) {
+
+                    /*
+                     * Increase capacity of index array.
+                     */
+                    run = Arrays.copyOf(run, count << 1);
+                }
+            }
+            run[count] = (last = k);
+        }
+
+        /*
+         * Merge runs of highly structured array.
+         */
+        if (count > 1) {
+            float[] b; int offset = low;
+
+            if (sorter == null || (b = (float[]) sorter.b) == null) {
+                b = new float[size];
+            } else {
+                offset = sorter.offset;
+            }
+            mergeRuns(a, b, offset, 1, sorter != null, run, 0, count);
+        }
+        return true;
+    }
+
+    /**
+     * Merges the specified runs.
+     *
+     * @param a the source array
+     * @param b the temporary buffer used in merging
+     * @param offset the start index in the source, inclusive
+     * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0)
+     * @param parallel indicates whether merging is performed in parallel
+     * @param run the start indexes of the runs, inclusive
+     * @param lo the start index of the first run, inclusive
+     * @param hi the start index of the last run, inclusive
+     * @return the destination where runs are merged
+     */
+    private static float[] mergeRuns(float[] a, float[] b, int offset,
+            int aim, boolean parallel, int[] run, int lo, int hi) {
+
+        if (hi - lo == 1) {
+            if (aim >= 0) {
+                return a;
+            }
+            for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+                b[--j] = a[--i]
+            );
+            return b;
+        }
+
+        /*
+         * Split into approximately equal parts.
+         */
+        int mi = lo, rmi = (run[lo] + run[hi]) >>> 1;
+        while (run[++mi + 1] <= rmi);
+
+        /*
+         * Merge the left and right parts.
+         */
+        float[] a1, a2;
+
+        if (parallel && hi - lo > MIN_RUN_COUNT) {
+            RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe();
+            a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi);
+            a2 = (float[]) merger.getDestination();
+        } else {
+            a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi);
+            a2 = mergeRuns(a, b, offset,    0, false, run, mi, hi);
+        }
+
+        float[] dst = a1 == a ? b : a;
+
+        int k   = a1 == a ? run[lo] - offset : run[lo];
+        int lo1 = a1 == b ? run[lo] - offset : run[lo];
+        int hi1 = a1 == b ? run[mi] - offset : run[mi];
+        int lo2 = a2 == b ? run[mi] - offset : run[mi];
+        int hi2 = a2 == b ? run[hi] - offset : run[hi];
+
+        if (parallel) {
+            new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke();
+        } else {
+            mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2);
+        }
+        return dst;
+    }
+
+    /**
+     * Merges the sorted parts.
+     *
+     * @param merger parallel context
+     * @param dst the destination where parts are merged
+     * @param k the start index of the destination, inclusive
+     * @param a1 the first part
+     * @param lo1 the start index of the first part, inclusive
+     * @param hi1 the end index of the first part, exclusive
+     * @param a2 the second part
+     * @param lo2 the start index of the second part, inclusive
+     * @param hi2 the end index of the second part, exclusive
+     */
+    private static void mergeParts(Merger merger, float[] dst, int k,
+            float[] a1, int lo1, int hi1, float[] a2, int lo2, int hi2) {
+
+        if (merger != null && a1 == a2) {
+
+            while (true) {
+
+                /*
+                 * The first part must be larger.
+                 */
+                if (hi1 - lo1 < hi2 - lo2) {
+                    int lo = lo1; lo1 = lo2; lo2 = lo;
+                    int hi = hi1; hi1 = hi2; hi2 = hi;
+                }
+
+                /*
+                 * Small parts will be merged sequentially.
+                 */
+                if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) {
+                    break;
+                }
+
+                /*
+                 * Find the median of the larger part.
+                 */
+                int mi1 = (lo1 + hi1) >>> 1;
+                float key = a1[mi1];
+                int mi2 = hi2;
+
+                /*
+                 * Partition the smaller part.
+                 */
+                for (int loo = lo2; loo < mi2; ) {
+                    int t = (loo + mi2) >>> 1;
+
+                    if (key > a2[t]) {
+                        loo = t + 1;
+                    } else {
+                        mi2 = t;
+                    }
+                }
+
+                int d = mi2 - lo2 + mi1 - lo1;
+
+                /*
+                 * Merge the right sub-parts in parallel.
+                 */
+                merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2);
+
+                /*
+                 * Process the sub-left parts.
+                 */
+                hi1 = mi1;
+                hi2 = mi2;
+            }
+        }
+
+        /*
+         * Merge small parts sequentially.
+         */
+        while (lo1 < hi1 && lo2 < hi2) {
+            dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++];
+        }
+        if (dst != a1 || k < lo1) {
+            while (lo1 < hi1) {
+                dst[k++] = a1[lo1++];
+            }
+        }
+        if (dst != a2 || k < lo2) {
+            while (lo2 < hi2) {
+                dst[k++] = a2[lo2++];
+            }
+        }
+    }
+
+// [double]
+
+    /**
+     * Sorts the specified range of the array using parallel merge
+     * sort and/or Dual-Pivot Quicksort.
+     *
+     * To balance the faster splitting and parallelism of merge sort
+     * with the faster element partitioning of Quicksort, ranges are
+     * subdivided in tiers such that, if there is enough parallelism,
+     * the four-way parallel merge is started, still ensuring enough
+     * parallelism to process the partitions.
+     *
+     * @param a the array to be sorted
+     * @param parallelism the parallelism level
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(double[] a, int parallelism, int low, int high) {
+        /*
+         * Phase 1. Count the number of negative zero -0.0d,
+         * turn them into positive zero, and move all NaNs
+         * to the end of the array.
+         */
+        int numNegativeZero = 0;
+
+        for (int k = high; k > low; ) {
+            double ak = a[--k];
+
+            if (ak == 0.0d && Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d
+                numNegativeZero += 1;
+                a[k] = 0.0d;
+            } else if (ak != ak) { // ak is NaN
+                a[k] = a[--high];
+                a[high] = ak;
+            }
+        }
+
+        /*
+         * Phase 2. Sort everything except NaNs,
+         * which are already in place.
+         */
+        int size = high - low;
+
+        if (parallelism > 1 && size > MIN_PARALLEL_SORT_SIZE) {
+            int depth = getDepth(parallelism, size >> 12);
+            double[] b = depth == 0 ? null : new double[size];
+            new Sorter(null, a, b, low, size, low, depth).invoke();
+        } else {
+            sort(null, a, 0, low, high);
+        }
+
+        /*
+         * Phase 3. Turn positive zero 0.0d
+         * back into negative zero -0.0d.
+         */
+        if (++numNegativeZero == 1) {
+            return;
+        }
+
+        /*
+         * Find the position one less than
+         * the index of the first zero.
+         */
+        while (low <= high) {
+            int middle = (low + high) >>> 1;
+
+            if (a[middle] < 0) {
+                low = middle + 1;
+            } else {
+                high = middle - 1;
+            }
+        }
+
+        /*
+         * Replace the required number of 0.0d by -0.0d.
+         */
+        while (--numNegativeZero > 0) {
+            a[++high] = -0.0d;
+        }
+    }
+
+    /**
+     * Sorts the specified array using the Dual-Pivot Quicksort and/or
+     * other sorts in special-cases, possibly with parallel partitions.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param bits the combination of recursion depth and bit flag, where
+     *        the right bit "0" indicates that array is the leftmost part
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    static void sort(Sorter sorter, double[] a, int bits, int low, int high) {
+        while (true) {
+            int end = high - 1, size = high - low;
+
+            /*
+             * Run mixed insertion sort on small non-leftmost parts.
+             */
+            if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) {
+                mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high);
+                return;
+            }
+
+            /*
+             * Invoke insertion sort on small leftmost part.
+             */
+            if (size < MAX_INSERTION_SORT_SIZE) {
+                insertionSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Check if the whole array or large non-leftmost
+             * parts are nearly sorted and then merge runs.
+             */
+            if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0)
+                    && tryMergeRuns(sorter, a, low, size)) {
+                return;
+            }
+
+            /*
+             * Switch to heap sort if execution
+             * time is becoming quadratic.
+             */
+            if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
+                heapSort(a, low, high);
+                return;
+            }
+
+            /*
+             * Use an inexpensive approximation of the golden ratio
+             * to select five sample elements and determine pivots.
+             */
+            int step = (size >> 3) * 3 + 3;
+
+            /*
+             * Five elements around (and including) the central element
+             * will be used for pivot selection as described below. The
+             * unequal choice of spacing these elements was empirically
+             * determined to work well on a wide variety of inputs.
+             */
+            int e1 = low + step;
+            int e5 = end - step;
+            int e3 = (e1 + e5) >>> 1;
+            int e2 = (e1 + e3) >>> 1;
+            int e4 = (e3 + e5) >>> 1;
+            double a3 = a[e3];
+
+            /*
+             * Sort these elements in place by the combination
+             * of 4-element sorting network and insertion sort.
+             *
+             *    5 ------o-----------o------------
+             *            |           |
+             *    4 ------|-----o-----o-----o------
+             *            |     |           |
+             *    2 ------o-----|-----o-----o------
+             *                  |     |
+             *    1 ------------o-----o------------
+             */
+            if (a[e5] < a[e2]) { double t = a[e5]; a[e5] = a[e2]; a[e2] = t; }
+            if (a[e4] < a[e1]) { double t = a[e4]; a[e4] = a[e1]; a[e1] = t; }
+            if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+            if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+            if (a[e4] < a[e2]) { double t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+
+            if (a3 < a[e2]) {
+                if (a3 < a[e1]) {
+                    a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3;
+                } else {
+                    a[e3] = a[e2]; a[e2] = a3;
+                }
+            } else if (a3 > a[e4]) {
+                if (a3 > a[e5]) {
+                    a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3;
+                } else {
+                    a[e3] = a[e4]; a[e4] = a3;
+                }
+            }
+
+            // Pointers
+            int lower = low; // The index of the last element of the left part
+            int upper = end; // The index of the first element of the right part
+
+            /*
+             * Partitioning with 2 pivots in case of different elements.
+             */
+            if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
+
+                /*
+                 * Use the first and fifth of the five sorted elements as
+                 * the pivots. These values are inexpensive approximation
+                 * of tertiles. Note, that pivot1 < pivot2.
+                 */
+                double pivot1 = a[e1];
+                double pivot2 = a[e5];
+
+                /*
+                 * The first and the last elements to be sorted are moved
+                 * to the locations formerly occupied by the pivots. When
+                 * partitioning is completed, the pivots are swapped back
+                 * into their final positions, and excluded from the next
+                 * subsequent sorting.
+                 */
+                a[e1] = a[lower];
+                a[e5] = a[upper];
+
+                /*
+                 * Skip elements, which are less or greater than the pivots.
+                 */
+                while (a[++lower] < pivot1);
+                while (a[--upper] > pivot2);
+
+                /*
+                 * Backward 3-interval partitioning
+                 *
+                 *   left part                 central part          right part
+                 * +------------------------------------------------------------+
+                 * |  < pivot1  |   ?   |  pivot1 <= && <= pivot2  |  > pivot2  |
+                 * +------------------------------------------------------------+
+                 *             ^       ^                            ^
+                 *             |       |                            |
+                 *           lower     k                          upper
+                 *
+                 * Invariants:
+                 *
+                 *              all in (low, lower] < pivot1
+                 *    pivot1 <= all in (k, upper)  <= pivot2
+                 *              all in [upper, end) > pivot2
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int unused = --lower, k = ++upper; --k > lower; ) {
+                    double ak = a[k];
+
+                    if (ak < pivot1) { // Move a[k] to the left side
+                        while (lower < k) {
+                            if (a[++lower] >= pivot1) {
+                                if (a[lower] > pivot2) {
+                                    a[k] = a[--upper];
+                                    a[upper] = a[lower];
+                                } else {
+                                    a[k] = a[lower];
+                                }
+                                a[lower] = ak;
+                                break;
+                            }
+                        }
+                    } else if (ak > pivot2) { // Move a[k] to the right side
+                        a[k] = a[--upper];
+                        a[upper] = ak;
+                    }
+                }
+
+                /*
+                 * Swap the pivots into their final positions.
+                 */
+                a[low] = a[lower]; a[lower] = pivot1;
+                a[end] = a[upper]; a[upper] = pivot2;
+
+                /*
+                 * Sort non-left parts recursively (possibly in parallel),
+                 * excluding known pivots.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, lower + 1, upper);
+                    sorter.forkSorter(bits | 1, upper + 1, high);
+                } else {
+                    sort(sorter, a, bits | 1, lower + 1, upper);
+                    sort(sorter, a, bits | 1, upper + 1, high);
+                }
+
+            } else { // Use single pivot in case of many equal elements
+
+                /*
+                 * Use the third of the five sorted elements as the pivot.
+                 * This value is inexpensive approximation of the median.
+                 */
+                double pivot = a[e3];
+
+                /*
+                 * The first element to be sorted is moved to the
+                 * location formerly occupied by the pivot. After
+                 * completion of partitioning the pivot is swapped
+                 * back into its final position, and excluded from
+                 * the next subsequent sorting.
+                 */
+                a[e3] = a[lower];
+
+                /*
+                 * Traditional 3-way (Dutch National Flag) partitioning
+                 *
+                 *   left part                 central part    right part
+                 * +------------------------------------------------------+
+                 * |   < pivot   |     ?     |   == pivot   |   > pivot   |
+                 * +------------------------------------------------------+
+                 *              ^           ^                ^
+                 *              |           |                |
+                 *            lower         k              upper
+                 *
+                 * Invariants:
+                 *
+                 *   all in (low, lower] < pivot
+                 *   all in (k, upper)  == pivot
+                 *   all in [upper, end] > pivot
+                 *
+                 * Pointer k is the last index of ?-part
+                 */
+                for (int k = ++upper; --k > lower; ) {
+                    double ak = a[k];
+
+                    if (ak != pivot) {
+                        a[k] = pivot;
+
+                        if (ak < pivot) { // Move a[k] to the left side
+                            while (a[++lower] < pivot);
+
+                            if (a[lower] > pivot) {
+                                a[--upper] = a[lower];
+                            }
+                            a[lower] = ak;
+                        } else { // ak > pivot - Move a[k] to the right side
+                            a[--upper] = ak;
+                        }
+                    }
+                }
+
+                /*
+                 * Swap the pivot into its final position.
+                 */
+                a[low] = a[lower]; a[lower] = pivot;
+
+                /*
+                 * Sort the right part (possibly in parallel), excluding
+                 * known pivot. All elements from the central part are
+                 * equal and therefore already sorted.
+                 */
+                if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) {
+                    sorter.forkSorter(bits | 1, upper, high);
+                } else {
+                    sort(sorter, a, bits | 1, upper, high);
+                }
+            }
+            high = lower; // Iterate along the left part
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using mixed insertion sort.
+     *
+     * Mixed insertion sort is combination of simple insertion sort,
+     * pin insertion sort and pair insertion sort.
+     *
+     * In the context of Dual-Pivot Quicksort, the pivot element
+     * from the left part plays the role of sentinel, because it
+     * is less than any elements from the given part. Therefore,
+     * expensive check of the left range can be skipped on each
+     * iteration unless it is the leftmost call.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param end the index of the last element for simple insertion sort
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void mixedInsertionSort(double[] a, int low, int end, int high) {
+        if (end == high) {
+
+            /*
+             * Invoke simple insertion sort on tiny array.
+             */
+            for (int i; ++low < end; ) {
+                double ai = a[i = low];
+
+                while (ai < a[--i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        } else {
+
+            /*
+             * Start with pin insertion sort on small part.
+             *
+             * Pin insertion sort is extended simple insertion sort.
+             * The main idea of this sort is to put elements larger
+             * than an element called pin to the end of array (the
+             * proper area for such elements). It avoids expensive
+             * movements of these elements through the whole array.
+             */
+            double pin = a[end];
+
+            for (int i, p = high; ++low < end; ) {
+                double ai = a[i = low];
+
+                if (ai < a[i - 1]) { // Small element
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    a[i] = a[--i];
+
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+
+                } else if (p > i && ai > pin) { // Large element
+
+                    /*
+                     * Find element smaller than pin.
+                     */
+                    while (a[--p] > pin);
+
+                    /*
+                     * Swap it with large element.
+                     */
+                    if (p > i) {
+                        ai = a[p];
+                        a[p] = a[i];
+                    }
+
+                    /*
+                     * Insert small element into sorted part.
+                     */
+                    while (ai < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = ai;
+                }
+            }
+
+            /*
+             * Continue with pair insertion sort on remain part.
+             */
+            for (int i; low < high; ++low) {
+                double a1 = a[i = low], a2 = a[++low];
+
+                /*
+                 * Insert two elements per iteration: at first, insert the
+                 * larger element and then insert the smaller element, but
+                 * from the position where the larger element was inserted.
+                 */
+                if (a1 > a2) {
+
+                    while (a1 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a1;
+
+                    while (a2 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a2;
+
+                } else if (a1 < a[i - 1]) {
+
+                    while (a2 < a[--i]) {
+                        a[i + 2] = a[i];
+                    }
+                    a[++i + 1] = a2;
+
+                    while (a1 < a[--i]) {
+                        a[i + 1] = a[i];
+                    }
+                    a[i + 1] = a1;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using insertion sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void insertionSort(double[] a, int low, int high) {
+        for (int i, k = low; ++k < high; ) {
+            double ai = a[i = k];
+
+            if (ai < a[i - 1]) {
+                while (--i >= low && ai < a[i]) {
+                    a[i + 1] = a[i];
+                }
+                a[i + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using heap sort.
+     *
+     * @param a the array to be sorted
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void heapSort(double[] a, int low, int high) {
+        for (int k = (low + high) >>> 1; k > low; ) {
+            pushDown(a, --k, a[k], low, high);
+        }
+        while (--high > low) {
+            double max = a[low];
+            pushDown(a, low, a[high], low, high);
+            a[high] = max;
+        }
+    }
+
+    /**
+     * Pushes specified element down during heap sort.
+     *
+     * @param a the given array
+     * @param p the start index
+     * @param value the given element
+     * @param low the index of the first element, inclusive, to be sorted
+     * @param high the index of the last element, exclusive, to be sorted
+     */
+    private static void pushDown(double[] a, int p, double value, int low, int high) {
+        for (int k ;; a[p] = a[p = k]) {
+            k = (p << 1) - low + 2; // Index of the right child
+
+            if (k > high) {
+                break;
+            }
+            if (k == high || a[k] < a[k - 1]) {
+                --k;
+            }
+            if (a[k] <= value) {
+                break;
+            }
+        }
+        a[p] = value;
+    }
+
+    /**
+     * Tries to sort the specified range of the array.
+     *
+     * @param sorter parallel context
+     * @param a the array to be sorted
+     * @param low the index of the first element to be sorted
+     * @param size the array size
+     * @return true if finally sorted, false otherwise
+     */
+    private static boolean tryMergeRuns(Sorter sorter, double[] a, int low, int size) {
+
+        /*
+         * The run array is constructed only if initial runs are
+         * long enough to continue, run[i] then holds start index
+         * of the i-th sequence of elements in non-descending order.
+         */
+        int[] run = null;
+        int high = low + size;
+        int count = 1, last = low;
+
+        /*
+         * Identify all possible runs.
+         */
+        for (int k = low + 1; k < high; ) {
+
+            /*
+             * Find the end index of the current run.
+             */
+            if (a[k - 1] < a[k]) {
+
+                // Identify ascending sequence
+                while (++k < high && a[k - 1] <= a[k]);
+
+            } else if (a[k - 1] > a[k]) {
+
+                // Identify descending sequence
+                while (++k < high && a[k - 1] >= a[k]);
+
+                // Reverse into ascending order
+                for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+                    double ai = a[i]; a[i] = a[j]; a[j] = ai;
+                }
+            } else { // Identify constant sequence
+                for (double ak = a[k]; ++k < high && ak == a[k]; );
+
+                if (k < high) {
+                    continue;
+                }
+            }
+
+            /*
+             * Check special cases.
+             */
+            if (run == null) {
+                if (k == high) {
+
+                    /*
+                     * The array is monotonous sequence,
+                     * and therefore already sorted.
+                     */
+                    return true;
+                }
+
+                if (k - low < MIN_FIRST_RUN_SIZE) {
+
+                    /*
+                     * The first run is too small
+                     * to proceed with scanning.
+                     */
+                    return false;
+                }
+
+                run = new int[((size >> 10) | 0x7F) & 0x3FF];
+                run[0] = low;
+
+            } else if (a[last - 1] > a[last]) {
+
+                if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) {
+
+                    /*
+                     * The first runs are not long
+                     * enough to continue scanning.
+                     */
+                    return false;
+                }
+
+                if (++count == MAX_RUN_CAPACITY) {
+
+                    /*
+                     * Array is not highly structured.
+                     */
+                    return false;
+                }
+
+                if (count == run.length) {
+
+                    /*
+                     * Increase capacity of index array.
+                     */
+                    run = Arrays.copyOf(run, count << 1);
+                }
+            }
+            run[count] = (last = k);
+        }
+
+        /*
+         * Merge runs of highly structured array.
+         */
+        if (count > 1) {
+            double[] b; int offset = low;
+
+            if (sorter == null || (b = (double[]) sorter.b) == null) {
+                b = new double[size];
+            } else {
+                offset = sorter.offset;
+            }
+            mergeRuns(a, b, offset, 1, sorter != null, run, 0, count);
+        }
+        return true;
+    }
+
+    /**
+     * Merges the specified runs.
+     *
+     * @param a the source array
+     * @param b the temporary buffer used in merging
+     * @param offset the start index in the source, inclusive
+     * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0)
+     * @param parallel indicates whether merging is performed in parallel
+     * @param run the start indexes of the runs, inclusive
+     * @param lo the start index of the first run, inclusive
+     * @param hi the start index of the last run, inclusive
+     * @return the destination where runs are merged
+     */
+    private static double[] mergeRuns(double[] a, double[] b, int offset,
+            int aim, boolean parallel, int[] run, int lo, int hi) {
+
+        if (hi - lo == 1) {
+            if (aim >= 0) {
+                return a;
+            }
+            for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+                b[--j] = a[--i]
+            );
+            return b;
+        }
+
+        /*
+         * Split into approximately equal parts.
+         */
+        int mi = lo, rmi = (run[lo] + run[hi]) >>> 1;
+        while (run[++mi + 1] <= rmi);
+
+        /*
+         * Merge the left and right parts.
+         */
+        double[] a1, a2;
+
+        if (parallel && hi - lo > MIN_RUN_COUNT) {
+            RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe();
+            a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi);
+            a2 = (double[]) merger.getDestination();
+        } else {
+            a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi);
+            a2 = mergeRuns(a, b, offset,    0, false, run, mi, hi);
+        }
+
+        double[] dst = a1 == a ? b : a;
+
+        int k   = a1 == a ? run[lo] - offset : run[lo];
+        int lo1 = a1 == b ? run[lo] - offset : run[lo];
+        int hi1 = a1 == b ? run[mi] - offset : run[mi];
+        int lo2 = a2 == b ? run[mi] - offset : run[mi];
+        int hi2 = a2 == b ? run[hi] - offset : run[hi];
+
+        if (parallel) {
+            new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke();
+        } else {
+            mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2);
+        }
+        return dst;
+    }
+
+    /**
+     * Merges the sorted parts.
+     *
+     * @param merger parallel context
+     * @param dst the destination where parts are merged
+     * @param k the start index of the destination, inclusive
+     * @param a1 the first part
+     * @param lo1 the start index of the first part, inclusive
+     * @param hi1 the end index of the first part, exclusive
+     * @param a2 the second part
+     * @param lo2 the start index of the second part, inclusive
+     * @param hi2 the end index of the second part, exclusive
+     */
+    private static void mergeParts(Merger merger, double[] dst, int k,
+            double[] a1, int lo1, int hi1, double[] a2, int lo2, int hi2) {
+
+        if (merger != null && a1 == a2) {
+
+            while (true) {
+
+                /*
+                 * The first part must be larger.
+                 */
+                if (hi1 - lo1 < hi2 - lo2) {
+                    int lo = lo1; lo1 = lo2; lo2 = lo;
+                    int hi = hi1; hi1 = hi2; hi2 = hi;
+                }
+
+                /*
+                 * Small parts will be merged sequentially.
+                 */
+                if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) {
+                    break;
+                }
+
+                /*
+                 * Find the median of the larger part.
+                 */
+                int mi1 = (lo1 + hi1) >>> 1;
+                double key = a1[mi1];
+                int mi2 = hi2;
+
+                /*
+                 * Partition the smaller part.
+                 */
+                for (int loo = lo2; loo < mi2; ) {
+                    int t = (loo + mi2) >>> 1;
+
+                    if (key > a2[t]) {
+                        loo = t + 1;
+                    } else {
+                        mi2 = t;
+                    }
+                }
+
+                int d = mi2 - lo2 + mi1 - lo1;
+
+                /*
+                 * Merge the right sub-parts in parallel.
+                 */
+                merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2);
+
+                /*
+                 * Process the sub-left parts.
+                 */
+                hi1 = mi1;
+                hi2 = mi2;
+            }
+        }
+
+        /*
+         * Merge small parts sequentially.
+         */
+        while (lo1 < hi1 && lo2 < hi2) {
+            dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++];
+        }
+        if (dst != a1 || k < lo1) {
+            while (lo1 < hi1) {
+                dst[k++] = a1[lo1++];
+            }
+        }
+        if (dst != a2 || k < lo2) {
+            while (lo2 < hi2) {
+                dst[k++] = a2[lo2++];
+            }
+        }
+    }
+
+// [class]
+
+    /**
+     * This class implements parallel sorting.
+     */
+    private static final class Sorter extends CountedCompleter<Void> {
+        private static final long serialVersionUID = 20180818L;
+        private final Object a, b;
+        private final int low, size, offset, depth;
+
+        private Sorter(CountedCompleter<?> parent,
+                Object a, Object b, int low, int size, int offset, int depth) {
+            super(parent);
+            this.a = a;
+            this.b = b;
+            this.low = low;
+            this.size = size;
+            this.offset = offset;
+            this.depth = depth;
+        }
+
+        @Override
+        public final void compute() {
+            if (depth < 0) {
+                setPendingCount(2);
+                int half = size >> 1;
+                new Sorter(this, b, a, low, half, offset, depth + 1).fork();
+                new Sorter(this, b, a, low + half, size - half, offset, depth + 1).compute();
+            } else {
+                if (a instanceof int[]) {
+                    sort(this, (int[]) a, depth, low, low + size);
+                } else if (a instanceof long[]) {
+                    sort(this, (long[]) a, depth, low, low + size);
+                } else if (a instanceof float[]) {
+                    sort(this, (float[]) a, depth, low, low + size);
+                } else if (a instanceof double[]) {
+                    sort(this, (double[]) a, depth, low, low + size);
+                } else {
+                    throw new IllegalArgumentException(
+                        "Unknown type of array: " + a.getClass().getName());
+                }
+            }
+            tryComplete();
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (depth < 0) {
+                int mi = low + (size >> 1);
+                boolean src = (depth & 1) == 0;
+
+                new Merger(null,
+                    a,
+                    src ? low : low - offset,
+                    b,
+                    src ? low - offset : low,
+                    src ? mi - offset : mi,
+                    b,
+                    src ? mi - offset : mi,
+                    src ? low + size - offset : low + size
+                ).invoke();
+            }
+        }
+
+        private void forkSorter(int depth, int low, int high) {
+            addToPendingCount(1);
+            Object a = this.a; // Use local variable for performance
+            new Sorter(this, a, b, low, high - low, offset, depth).fork();
+        }
+    }
+
+    /**
+     * This class implements parallel merging.
+     */
+    private static final class Merger extends CountedCompleter<Void> {
+        private static final long serialVersionUID = 20180818L;
+        private final Object dst, a1, a2;
+        private final int k, lo1, hi1, lo2, hi2;
+
+        private Merger(CountedCompleter<?> parent, Object dst, int k,
+                Object a1, int lo1, int hi1, Object a2, int lo2, int hi2) {
+            super(parent);
+            this.dst = dst;
+            this.k = k;
+            this.a1 = a1;
+            this.lo1 = lo1;
+            this.hi1 = hi1;
+            this.a2 = a2;
+            this.lo2 = lo2;
+            this.hi2 = hi2;
+        }
+
+        @Override
+        public final void compute() {
+            if (dst instanceof int[]) {
+                mergeParts(this, (int[]) dst, k,
+                    (int[]) a1, lo1, hi1, (int[]) a2, lo2, hi2);
+            } else if (dst instanceof long[]) {
+                mergeParts(this, (long[]) dst, k,
+                    (long[]) a1, lo1, hi1, (long[]) a2, lo2, hi2);
+            } else if (dst instanceof float[]) {
+                mergeParts(this, (float[]) dst, k,
+                    (float[]) a1, lo1, hi1, (float[]) a2, lo2, hi2);
+            } else if (dst instanceof double[]) {
+                mergeParts(this, (double[]) dst, k,
+                    (double[]) a1, lo1, hi1, (double[]) a2, lo2, hi2);
+            } else {
+                throw new IllegalArgumentException(
+                    "Unknown type of array: " + dst.getClass().getName());
+            }
+            propagateCompletion();
+        }
+
+        private void forkMerger(Object dst, int k,
+                Object a1, int lo1, int hi1, Object a2, int lo2, int hi2) {
+            addToPendingCount(1);
+            new Merger(this, dst, k, a1, lo1, hi1, a2, lo2, hi2).fork();
+        }
+    }
+
+    /**
+     * This class implements parallel merging of runs.
+     */
+    private static final class RunMerger extends RecursiveTask<Object> {
+        private static final long serialVersionUID = 20180818L;
+        private final Object a, b;
+        private final int[] run;
+        private final int offset, aim, lo, hi;
+
+        private RunMerger(Object a, Object b, int offset,
+                int aim, int[] run, int lo, int hi) {
+            this.a = a;
+            this.b = b;
+            this.offset = offset;
+            this.aim = aim;
+            this.run = run;
+            this.lo = lo;
+            this.hi = hi;
+        }
+
+        @Override
+        protected final Object compute() {
+            if (a instanceof int[]) {
+                return mergeRuns((int[]) a, (int[]) b, offset, aim, true, run, lo, hi);
+            }
+            if (a instanceof long[]) {
+                return mergeRuns((long[]) a, (long[]) b, offset, aim, true, run, lo, hi);
+            }
+            if (a instanceof float[]) {
+                return mergeRuns((float[]) a, (float[]) b, offset, aim, true, run, lo, hi);
+            }
+            if (a instanceof double[]) {
+                return mergeRuns((double[]) a, (double[]) b, offset, aim, true, run, lo, hi);
+            }
+            throw new IllegalArgumentException(
+                "Unknown type of array: " + a.getClass().getName());
+        }
+
+        private RunMerger forkMe() {
+            fork();
+            return this;
+        }
+
+        private Object getDestination() {
+            join();
+            return getRawResult();
+        }
+    }
+}
diff --git a/android-35/java/util/DuplicateFormatFlagsException.java b/android-35/java/util/DuplicateFormatFlagsException.java
new file mode 100644
index 0000000..356ea20
--- /dev/null
+++ b/android-35/java/util/DuplicateFormatFlagsException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when duplicate flags are provided in the format
+ * specifier.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class DuplicateFormatFlagsException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 18890531L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain a duplicate flag.
+     */
+    public DuplicateFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains a duplicate flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return String.format("Flags = '%s'", flags);
+    }
+}
diff --git a/android-35/java/util/EmptyStackException.java b/android-35/java/util/EmptyStackException.java
new file mode 100644
index 0000000..6c74521
--- /dev/null
+++ b/android-35/java/util/EmptyStackException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in the {@code Stack} class to indicate
+ * that the stack is empty.
+ *
+ * @author  Jonathan Payne
+ * @see     java.util.Stack
+ * @since   1.0
+ */
+public class EmptyStackException extends RuntimeException {
+    @java.io.Serial
+    private static final long serialVersionUID = 5084686378493302095L;
+
+    /**
+     * Constructs a new {@code EmptyStackException} with {@code null}
+     * as its error message string.
+     */
+    public EmptyStackException() {
+    }
+}
diff --git a/android-35/java/util/EnumMap.java b/android-35/java/util/EnumMap.java
new file mode 100644
index 0000000..640d248
--- /dev/null
+++ b/android-35/java/util/EnumMap.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * A specialized {@link Map} implementation for use with enum type keys.  All
+ * of the keys in an enum map must come from a single enum type that is
+ * specified, explicitly or implicitly, when the map is created.  Enum maps
+ * are represented internally as arrays.  This representation is extremely
+ * compact and efficient.
+ *
+ * <p>Enum maps are maintained in the <i>natural order</i> of their keys
+ * (the order in which the enum constants are declared).  This is reflected
+ * in the iterators returned by the collections views ({@link #keySet()},
+ * {@link #entrySet()}, and {@link #values()}).
+ *
+ * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
+ * they will never throw {@link ConcurrentModificationException} and they may
+ * or may not show the effects of any modifications to the map that occur while
+ * the iteration is in progress.
+ *
+ * <p>Null keys are not permitted.  Attempts to insert a null key will
+ * throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null key or to remove one will, however, function properly.
+ * Null values are permitted.
+ *
+ * <P>Like most collection implementations {@code EnumMap} is not
+ * synchronized. If multiple threads access an enum map concurrently, and at
+ * least one of the threads modifies the map, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum map.  If no such object exists,
+ * the map should be "wrapped" using the {@link Collections#synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ *     Map&lt;EnumKey, V&gt; m
+ *         = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be faster than their
+ * {@link HashMap} counterparts.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @see EnumSet
+ * @since 1.5
+ */
+public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
+    implements java.io.Serializable, Cloneable
+{
+    /**
+     * The {@code Class} object for the enum type of all the keys of this map.
+     *
+     * @serial
+     */
+    private final Class<K> keyType;
+
+    /**
+     * All of the values comprising K.  (Cached for performance.)
+     */
+    private transient K[] keyUniverse;
+
+    /**
+     * Array representation of this map.  The ith element is the value
+     * to which universe[i] is currently mapped, or null if it isn't
+     * mapped to anything, or NULL if it's mapped to null.
+     */
+    private transient Object[] vals;
+
+    /**
+     * The number of mappings in this map.
+     */
+    private transient int size = 0;
+
+    /**
+     * Distinguished non-null value for representing null values.
+     */
+    private static final Object NULL = new Object() {
+        public int hashCode() {
+            return 0;
+        }
+
+        public String toString() {
+            return "java.util.EnumMap.NULL";
+        }
+    };
+
+    private Object maskNull(Object value) {
+        return (value == null ? NULL : value);
+    }
+
+    @SuppressWarnings("unchecked")
+    private V unmaskNull(Object value) {
+        return (V)(value == NULL ? null : value);
+    }
+
+    /**
+     * Creates an empty enum map with the specified key type.
+     *
+     * @param keyType the class object of the key type for this enum map
+     * @throws NullPointerException if {@code keyType} is null
+     */
+    public EnumMap(Class<K> keyType) {
+        this.keyType = keyType;
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+    }
+
+    /**
+     * Creates an enum map with the same key type as the specified enum
+     * map, initially containing the same mappings (if any).
+     *
+     * @param m the enum map from which to initialize this enum map
+     * @throws NullPointerException if {@code m} is null
+     */
+    public EnumMap(EnumMap<K, ? extends V> m) {
+        keyType = m.keyType;
+        keyUniverse = m.keyUniverse;
+        vals = m.vals.clone();
+        size = m.size;
+    }
+
+    /**
+     * Creates an enum map initialized from the specified map.  If the
+     * specified map is an {@code EnumMap} instance, this constructor behaves
+     * identically to {@link #EnumMap(EnumMap)}.  Otherwise, the specified map
+     * must contain at least one mapping (in order to determine the new
+     * enum map's key type).
+     *
+     * @param m the map from which to initialize this enum map
+     * @throws IllegalArgumentException if {@code m} is not an
+     *     {@code EnumMap} instance and contains no mappings
+     * @throws NullPointerException if {@code m} is null
+     */
+    public EnumMap(Map<K, ? extends V> m) {
+        if (m instanceof EnumMap) {
+            EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
+            keyType = em.keyType;
+            keyUniverse = em.keyUniverse;
+            vals = em.vals.clone();
+            size = em.size;
+        } else {
+            if (m.isEmpty())
+                throw new IllegalArgumentException("Specified map is empty");
+            keyType = m.keySet().iterator().next().getDeclaringClass();
+            keyUniverse = getKeyUniverse(keyType);
+            vals = new Object[keyUniverse.length];
+            putAll(m);
+        }
+    }
+
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value the value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to this value
+     */
+    public boolean containsValue(Object value) {
+        value = maskNull(value);
+
+        for (Object val : vals)
+            if (value.equals(val))
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key the key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified
+     *            key
+     */
+    public boolean containsKey(Object key) {
+        return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
+    }
+
+    private boolean containsMapping(Object key, Object value) {
+        return isValidKey(key) &&
+            maskNull(value).equals(vals[((Enum<?>)key).ordinal()]);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        return (isValidKey(key) ?
+                unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
+    }
+
+    // Modification Operations
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     *
+     * @return the previous value associated with specified key, or
+     *     {@code null} if there was no mapping for key.  (A {@code null}
+     *     return can also indicate that the map previously associated
+     *     {@code null} with the specified key.)
+     * @throws NullPointerException if the specified key is null
+     */
+    public V put(K key, V value) {
+        typeCheck(key);
+
+        int index = key.ordinal();
+        Object oldValue = vals[index];
+        vals[index] = maskNull(value);
+        if (oldValue == null)
+            size++;
+        return unmaskNull(oldValue);
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key the key whose mapping is to be removed from the map
+     * @return the previous value associated with specified key, or
+     *     {@code null} if there was no entry for key.  (A {@code null}
+     *     return can also indicate that the map previously associated
+     *     {@code null} with the specified key.)
+     */
+    public V remove(Object key) {
+        if (!isValidKey(key))
+            return null;
+        int index = ((Enum<?>)key).ordinal();
+        Object oldValue = vals[index];
+        vals[index] = null;
+        if (oldValue != null)
+            size--;
+        return unmaskNull(oldValue);
+    }
+
+    private boolean removeMapping(Object key, Object value) {
+        if (!isValidKey(key))
+            return false;
+        int index = ((Enum<?>)key).ordinal();
+        if (maskNull(value).equals(vals[index])) {
+            vals[index] = null;
+            size--;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if key is of the proper type to be a key in this
+     * enum map.
+     */
+    private boolean isValidKey(Object key) {
+        if (key == null)
+            return false;
+
+        // Cheaper than instanceof Enum followed by getDeclaringClass
+        Class<?> keyClass = key.getClass();
+        return keyClass == keyType || keyClass.getSuperclass() == keyType;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m the mappings to be stored in this map
+     * @throws NullPointerException the specified map is null, or if
+     *     one or more keys in the specified map are null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        if (m instanceof EnumMap<?, ?> em) {
+            if (em.keyType != keyType) {
+                if (em.isEmpty())
+                    return;
+                throw new ClassCastException(em.keyType + " != " + keyType);
+            }
+
+            for (int i = 0; i < keyUniverse.length; i++) {
+                Object emValue = em.vals[i];
+                if (emValue != null) {
+                    if (vals[i] == null)
+                        size++;
+                    vals[i] = emValue;
+                }
+            }
+        } else {
+            super.putAll(m);
+        }
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        Arrays.fill(vals, null);
+        size = 0;
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the keys
+     * in their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a set view of the keys contained in this enum map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            EnumMap.this.remove(o);
+            return size != oldSize;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The returned collection obeys the general contract outlined in
+     * {@link Map#values()}.  The collection's iterator will return the
+     * values in the order their corresponding keys appear in map,
+     * which is their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a collection view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            o = maskNull(o);
+
+            for (int i = 0; i < vals.length; i++) {
+                if (o.equals(vals[i])) {
+                    vals[i] = null;
+                    size--;
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the
+     * mappings in the order their keys appear in map, which is their
+     * natural order (the order in which the enum constants are declared).
+     *
+     * @return a set view of the mappings contained in this enum map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            return o instanceof Map.Entry<?, ?> entry
+                    && containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            return o instanceof Map.Entry<?, ?> entry
+                    && removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+        public Object[] toArray() {
+            return fillEntryArray(new Object[size]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), size);
+            if (a.length > size)
+                a[size] = null;
+            return (T[]) fillEntryArray(a);
+        }
+        private Object[] fillEntryArray(Object[] a) {
+            int j = 0;
+            for (int i = 0; i < vals.length; i++)
+                if (vals[i] != null)
+                    a[j++] = new AbstractMap.SimpleEntry<>(
+                        keyUniverse[i], unmaskNull(vals[i]));
+            return a;
+        }
+    }
+
+    private abstract class EnumMapIterator<T> implements Iterator<T> {
+        // Lower bound on index of next element to return
+        int index = 0;
+
+        // Index of last returned element, or -1 if none
+        int lastReturnedIndex = -1;
+
+        public boolean hasNext() {
+            while (index < vals.length && vals[index] == null)
+                index++;
+            return index != vals.length;
+        }
+
+        public void remove() {
+            checkLastReturnedIndex();
+
+            if (vals[lastReturnedIndex] != null) {
+                vals[lastReturnedIndex] = null;
+                size--;
+            }
+            lastReturnedIndex = -1;
+        }
+
+        private void checkLastReturnedIndex() {
+            if (lastReturnedIndex < 0)
+                throw new IllegalStateException();
+        }
+    }
+
+    private class KeyIterator extends EnumMapIterator<K> {
+        public K next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return keyUniverse[lastReturnedIndex];
+        }
+    }
+
+    private class ValueIterator extends EnumMapIterator<V> {
+        public V next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return unmaskNull(vals[lastReturnedIndex]);
+        }
+    }
+
+    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedEntry = new Entry(index++);
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            public K getKey() {
+                checkIndexForEntryUse();
+                return keyUniverse[index];
+            }
+
+            public V getValue() {
+                checkIndexForEntryUse();
+                return unmaskNull(vals[index]);
+            }
+
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = unmaskNull(vals[index]);
+                vals[index] = maskNull(value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return o == this;
+
+                if (!(o instanceof Map.Entry<?, ?> e))
+                    return false;
+
+                V ourValue = unmaskNull(vals[index]);
+                Object hisValue = e.getValue();
+                return (e.getKey() == keyUniverse[index] &&
+                        (ourValue == hisValue ||
+                         (ourValue != null && ourValue.equals(hisValue))));
+            }
+
+            public int hashCode() {
+                if (index < 0)
+                    return super.hashCode();
+
+                return entryHashCode(index);
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return keyUniverse[index] + "="
+                    + unmaskNull(vals[index]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent the same mappings, as specified in the {@link
+     * Map#equals(Object)} contract.
+     *
+     * @param o the object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o instanceof EnumMap)
+            return equals((EnumMap<?,?>)o);
+        if (!(o instanceof Map<?, ?> m))
+            return false;
+
+        if (size != m.size())
+            return false;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                K key = keyUniverse[i];
+                V value = unmaskNull(vals[i]);
+                if (null == value) {
+                    if (!((null == m.get(key)) && m.containsKey(key)))
+                       return false;
+                } else {
+                   if (!value.equals(m.get(key)))
+                      return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    private boolean equals(EnumMap<?,?> em) {
+        if (em.size != size)
+            return false;
+
+        if (em.keyType != keyType)
+            return size == 0;
+
+        // Key types match, compare each value
+        for (int i = 0; i < keyUniverse.length; i++) {
+            Object ourValue =    vals[i];
+            Object hisValue = em.vals[i];
+            if (hisValue != ourValue &&
+                (hisValue == null || !hisValue.equals(ourValue)))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map.
+     */
+    public int hashCode() {
+        int h = 0;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                h += entryHashCode(i);
+            }
+        }
+
+        return h;
+    }
+
+    private int entryHashCode(int index) {
+        return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
+    }
+
+    /**
+     * Returns a shallow copy of this enum map. The values themselves
+     * are not cloned.
+     *
+     * @return a shallow copy of this enum map
+     */
+    @SuppressWarnings("unchecked")
+    public EnumMap<K, V> clone() {
+        EnumMap<K, V> result = null;
+        try {
+            result = (EnumMap<K, V>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+        result.vals = result.vals.clone();
+        result.entrySet = null;
+        return result;
+    }
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    private void typeCheck(K key) {
+        Class<?> keyClass = key.getClass();
+        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
+            throw new ClassCastException(keyClass + " != " + keyType);
+    }
+
+    /**
+     * Returns all of the values comprising K.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return keyType.getEnumConstantsShared();
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 458661240069192865L;
+
+    /**
+     * Save the state of the {@code EnumMap} instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>size</i> of the enum map (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the enum map.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException
+    {
+        // Write out the key type and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        int entriesToBeWritten = size;
+        for (int i = 0; entriesToBeWritten > 0; i++) {
+            if (null != vals[i]) {
+                s.writeObject(keyUniverse[i]);
+                s.writeObject(unmaskNull(vals[i]));
+                entriesToBeWritten--;
+            }
+        }
+    }
+
+    /**
+     * Reconstitute the {@code EnumMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    @SuppressWarnings("unchecked")
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        // Read in the key type and any hidden stuff
+        s.defaultReadObject();
+
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+
+        // Read in size (number of Mappings)
+        int size = s.readInt();
+
+        // Read the keys and values, and put the mappings in the HashMap
+        for (int i = 0; i < size; i++) {
+            K key = (K) s.readObject();
+            V value = (V) s.readObject();
+            put(key, value);
+        }
+    }
+}
diff --git a/android-35/java/util/EnumSet.java b/android-35/java/util/EnumSet.java
new file mode 100644
index 0000000..75d21a0
--- /dev/null
+++ b/android-35/java/util/EnumSet.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * A specialized {@link Set} implementation for use with enum types.  All of
+ * the elements in an enum set must come from a single enum type that is
+ * specified, explicitly or implicitly, when the set is created.  Enum sets
+ * are represented internally as bit vectors.  This representation is
+ * extremely compact and efficient. The space and time performance of this
+ * class should be good enough to allow its use as a high-quality, typesafe
+ * alternative to traditional {@code int}-based "bit flags."  Even bulk
+ * operations (such as {@code containsAll} and {@code retainAll}) should
+ * run very quickly if their argument is also an enum set.
+ *
+ * <p>The iterator returned by the {@code iterator} method traverses the
+ * elements in their <i>natural order</i> (the order in which the enum
+ * constants are declared).  The returned iterator is <i>weakly
+ * consistent</i>: it will never throw {@link ConcurrentModificationException}
+ * and it may or may not show the effects of any modifications to the set that
+ * occur while the iteration is in progress.
+ *
+ * <p>Null elements are not permitted.  Attempts to insert a null element
+ * will throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null element or to remove one will, however, function
+ * properly.
+ *
+ * <P>Like most collection implementations, {@code EnumSet} is not
+ * synchronized.  If multiple threads access an enum set concurrently, and at
+ * least one of the threads modifies the set, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum set.  If no such object exists,
+ * the set should be "wrapped" using the {@link Collections#synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be much faster than their
+ * {@link HashSet} counterparts.  Even bulk operations execute in
+ * constant time if their argument is also an enum set.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @see EnumMap
+ */
+public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
+    implements Cloneable, java.io.Serializable
+{
+    // declare EnumSet.class serialization compatibility with JDK 8
+    @java.io.Serial
+    private static final long serialVersionUID = 1009687484059888093L;
+
+    /**
+     * The class of all the elements of this set.
+     */
+    final transient Class<E> elementType;
+
+    /**
+     * All of the values comprising E.  (Cached for performance.)
+     */
+    final transient Enum<?>[] universe;
+
+    EnumSet(Class<E>elementType, Enum<?>[] universe) {
+        this.elementType = elementType;
+        this.universe    = universe;
+    }
+
+    /**
+     * Creates an empty enum set with the specified element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An empty enum set of the specified type.
+     * @throws NullPointerException if {@code elementType} is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
+        Enum<?>[] universe = getUniverse(elementType);
+        if (universe == null)
+            throw new ClassCastException(elementType + " not an enum");
+
+        if (universe.length <= 64)
+            return new RegularEnumSet<>(elementType, universe);
+        else
+            return new JumboEnumSet<>(elementType, universe);
+    }
+
+    /**
+     * Creates an enum set containing all of the elements in the specified
+     * element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An enum set containing all the elements in the specified type.
+     * @throws NullPointerException if {@code elementType} is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
+        EnumSet<E> result = noneOf(elementType);
+        result.addAll();
+        return result;
+    }
+
+    /**
+     * Adds all of the elements from the appropriate enum type to this enum
+     * set, which is empty prior to the call.
+     */
+    abstract void addAll();
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing the same elements (if any).
+     *
+     * @param <E> The class of the elements in the set
+     * @param s the enum set from which to initialize this enum set
+     * @return A copy of the specified enum set.
+     * @throws NullPointerException if {@code s} is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
+        return s.clone();
+    }
+
+    /**
+     * Creates an enum set initialized from the specified collection.  If
+     * the specified collection is an {@code EnumSet} instance, this static
+     * factory method behaves identically to {@link #copyOf(EnumSet)}.
+     * Otherwise, the specified collection must contain at least one element
+     * (in order to determine the new enum set's element type).
+     *
+     * @param <E> The class of the elements in the collection
+     * @param c the collection from which to initialize this enum set
+     * @return An enum set initialized from the given collection.
+     * @throws IllegalArgumentException if {@code c} is not an
+     *     {@code EnumSet} instance and contains no elements
+     * @throws NullPointerException if {@code c} is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
+        if (c instanceof EnumSet) {
+            return ((EnumSet<E>)c).clone();
+        } else {
+            if (c.isEmpty())
+                throw new IllegalArgumentException("Collection is empty");
+            Iterator<E> i = c.iterator();
+            E first = i.next();
+            EnumSet<E> result = EnumSet.of(first);
+            while (i.hasNext())
+                result.add(i.next());
+            return result;
+        }
+    }
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing all the elements of this type that are
+     * <i>not</i> contained in the specified set.
+     *
+     * @param <E> The class of the elements in the enum set
+     * @param s the enum set from whose complement to initialize this enum set
+     * @return The complement of the specified set in this set
+     * @throws NullPointerException if {@code s} is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
+        EnumSet<E> result = copyOf(s);
+        result.complement();
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified element.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the specified element and of the set
+     * @param e the element that this set is to contain initially
+     * @throws NullPointerException if {@code e} is null
+     * @return an enum set initially containing the specified element
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e) {
+        EnumSet<E> result = noneOf(e.getDeclaringClass());
+        result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @param e5 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
+                                                    E e5)
+    {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        result.add(e5);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     * This factory, whose parameter list uses the varargs feature, may
+     * be used to create an enum set initially containing an arbitrary
+     * number of elements, but it is likely to run slower than the overloadings
+     * that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param first an element that the set is to contain initially
+     * @param rest the remaining elements the set is to contain initially
+     * @throws NullPointerException if any of the specified elements are null,
+     *     or if {@code rest} is null
+     * @return an enum set initially containing the specified elements
+     */
+    @SafeVarargs
+    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
+        EnumSet<E> result = noneOf(first.getDeclaringClass());
+        result.add(first);
+        for (E e : rest)
+            result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing all of the elements in the
+     * range defined by the two specified endpoints.  The returned set will
+     * contain the endpoints themselves, which may be identical but must not
+     * be out of order.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param from the first element in the range
+     * @param to the last element in the range
+     * @throws NullPointerException if {@code from} or {@code to} are null
+     * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
+     * @return an enum set initially containing all of the elements in the
+     *         range defined by the two specified endpoints
+     */
+    public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
+        if (from.compareTo(to) > 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        EnumSet<E> result = noneOf(from.getDeclaringClass());
+        result.addRange(from, to);
+        return result;
+    }
+
+    /**
+     * Adds the specified range to this enum set, which is empty prior
+     * to the call.
+     */
+    abstract void addRange(E from, E to);
+
+    /**
+     * Returns a copy of this set.
+     *
+     * @return a copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public EnumSet<E> clone() {
+        try {
+            return (EnumSet<E>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Complements the contents of this enum set.
+     */
+    abstract void complement();
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    final void typeCheck(E e) {
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            throw new ClassCastException(eClass + " != " + elementType);
+    }
+
+    /**
+     * Returns all of the values comprising E.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return elementType.getEnumConstantsShared();
+    }
+
+    /**
+     * This class is used to serialize all EnumSet instances, regardless of
+     * implementation type.  It captures their "logical contents" and they
+     * are reconstructed using public static factories.  This is necessary
+     * to ensure that the existence of a particular implementation type is
+     * an implementation detail.
+     *
+     * @serial include
+     */
+    private static class SerializationProxy<E extends Enum<E>>
+        implements java.io.Serializable
+    {
+
+        private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
+
+        /**
+         * The element type of this enum set.
+         *
+         * @serial
+         */
+        private final Class<E> elementType;
+
+        /**
+         * The elements contained in this enum set.
+         *
+         * @serial
+         */
+        private final Enum<?>[] elements;
+
+        SerializationProxy(EnumSet<E> set) {
+            elementType = set.elementType;
+            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
+        }
+
+        /**
+         * Returns an {@code EnumSet} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code EnumSet} object with initial state
+         * held by this proxy
+         */
+        @SuppressWarnings("unchecked")
+        @java.io.Serial
+        private Object readResolve() {
+            // instead of cast to E, we should perhaps use elementType.cast()
+            // to avoid injection of forged stream, but it will slow the
+            // implementation
+            EnumSet<E> result = EnumSet.noneOf(elementType);
+            for (Enum<?> e : elements)
+                result.add((E)e);
+            return result;
+        }
+
+        @java.io.Serial
+        private static final long serialVersionUID = 362491234563181265L;
+    }
+
+    /**
+     * Returns a
+     * <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    @java.io.Serial
+    Object writeReplace() {
+        return new SerializationProxy<>(this);
+    }
+
+    /**
+     * Throws {@code InvalidObjectException}.
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+    /**
+     * Throws {@code InvalidObjectException}.
+     * @throws java.io.InvalidObjectException always
+     */
+    @java.io.Serial
+    private void readObjectNoData()
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+}
diff --git a/android-35/java/util/Enumeration.java b/android-35/java/util/Enumeration.java
new file mode 100644
index 0000000..8d920c8
--- /dev/null
+++ b/android-35/java/util/Enumeration.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An object that implements the Enumeration interface generates a
+ * series of elements, one at a time. Successive calls to the
+ * {@code nextElement} method return successive elements of the
+ * series.
+ * <p>
+ * For example, to print all elements of a {@code Vector<E>} <i>v</i>:
+ * <pre>
+ *   for (Enumeration&lt;E&gt; e = v.elements(); e.hasMoreElements();)
+ *       System.out.println(e.nextElement());</pre>
+ * <p>
+ * Methods are provided to enumerate through the elements of a
+ * vector, the keys of a hashtable, and the values in a hashtable.
+ * Enumerations are also used to specify the input streams to a
+ * {@code SequenceInputStream}.
+ *
+ * @apiNote
+ * The functionality of this interface is duplicated by the {@link Iterator}
+ * interface.  In addition, {@code Iterator} adds an optional remove operation,
+ * and has shorter method names.  New implementations should consider using
+ * {@code Iterator} in preference to {@code Enumeration}. It is possible to
+ * adapt an {@code Enumeration} to an {@code Iterator} by using the
+ * {@link #asIterator} method.
+ *
+ * @see     java.util.Iterator
+ * @see     java.io.SequenceInputStream
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Hashtable
+ * @see     java.util.Hashtable#elements()
+ * @see     java.util.Hashtable#keys()
+ * @see     java.util.Vector
+ * @see     java.util.Vector#elements()
+ *
+ * @author  Lee Boynton
+ * @since   1.0
+ */
+public interface Enumeration<E> {
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return  {@code true} if and only if this enumeration object
+     *           contains at least one more element to provide;
+     *          {@code false} otherwise.
+     */
+    boolean hasMoreElements();
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * object has at least one more element to provide.
+     *
+     * @return     the next element of this enumeration.
+     * @throws     NoSuchElementException  if no more elements exist.
+     */
+    E nextElement();
+
+    /**
+     * Returns an {@link Iterator} that traverses the remaining elements
+     * covered by this enumeration. Traversal is undefined if any methods
+     * are called on this enumeration after the call to {@code asIterator}.
+     *
+     * @apiNote
+     * This method is intended to help adapt code that produces
+     * {@code Enumeration} instances to code that consumes {@code Iterator}
+     * instances. For example, the {@link java.util.jar.JarFile#entries()
+     * JarFile.entries()} method returns an {@code Enumeration<JarEntry>}.
+     * This can be turned into an {@code Iterator}, and then the
+     * {@code forEachRemaining()} method can be used:
+     *
+     * <pre>{@code
+     *     JarFile jarFile = ... ;
+     *     jarFile.entries().asIterator().forEachRemaining(entry -> { ... });
+     * }</pre>
+     *
+     * (Note that there is also a {@link java.util.jar.JarFile#stream()
+     * JarFile.stream()} method that returns a {@code Stream} of entries,
+     * which may be more convenient in some cases.)
+     *
+     * @implSpec
+     * The default implementation returns an {@code Iterator} whose
+     * {@link Iterator#hasNext hasNext} method calls this Enumeration's
+     * {@code hasMoreElements} method, whose {@link Iterator#next next}
+     * method calls this Enumeration's {@code nextElement} method, and
+     * whose {@link Iterator#remove remove} method throws
+     * {@code UnsupportedOperationException}.
+     *
+     * @return an Iterator representing the remaining elements of this Enumeration
+     *
+     * @since 9
+     */
+    default Iterator<E> asIterator() {
+        return new Iterator<>() {
+            @Override public boolean hasNext() {
+                return hasMoreElements();
+            }
+            @Override public E next() {
+                return nextElement();
+            }
+        };
+    }
+}
diff --git a/android-35/java/util/EventListener.java b/android-35/java/util/EventListener.java
new file mode 100644
index 0000000..9e51158
--- /dev/null
+++ b/android-35/java/util/EventListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A tagging interface that all event listener interfaces must extend.
+ * @since 1.1
+ */
+public interface EventListener {
+}
diff --git a/android-35/java/util/EventListenerProxy.java b/android-35/java/util/EventListenerProxy.java
new file mode 100644
index 0000000..c982367
--- /dev/null
+++ b/android-35/java/util/EventListenerProxy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An abstract wrapper class for an {@code EventListener} class
+ * which associates a set of additional parameters with the listener.
+ * Subclasses must provide the storage and accessor methods
+ * for the additional arguments or parameters.
+ * <p>
+ * For example, a bean which supports named properties
+ * would have a two argument method signature for adding
+ * a {@code PropertyChangeListener} for a property:
+ * <pre>
+ * public void addPropertyChangeListener(String propertyName,
+ *                                       PropertyChangeListener listener)
+ * </pre>
+ * If the bean also implemented the zero argument get listener method:
+ * <pre>
+ * public PropertyChangeListener[] getPropertyChangeListeners()
+ * </pre>
+ * then the array may contain inner {@code PropertyChangeListeners}
+ * which are also {@code PropertyChangeListenerProxy} objects.
+ * <p>
+ * If the calling method is interested in retrieving the named property
+ * then it would have to test the element to see if it is a proxy class.
+ *
+ * @since 1.4
+ */
+public abstract class EventListenerProxy<T extends EventListener>
+        implements EventListener {
+
+    private final T listener;
+
+    /**
+     * Creates a proxy for the specified listener.
+     *
+     * @param listener  the listener object
+     */
+    public EventListenerProxy(T listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * Returns the listener associated with the proxy.
+     *
+     * @return  the listener associated with the proxy
+     */
+    public T getListener() {
+        return this.listener;
+    }
+}
diff --git a/android-35/java/util/EventObject.java b/android-35/java/util/EventObject.java
new file mode 100644
index 0000000..a90688b
--- /dev/null
+++ b/android-35/java/util/EventObject.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The root class from which all event state objects shall be derived.
+ * <p>
+ * All Events are constructed with a reference to the object, the "source",
+ * that is logically deemed to be the object upon which the Event in question
+ * initially occurred upon.
+ *
+ * @since 1.1
+ */
+
+public class EventObject implements java.io.Serializable {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 5516075349620653480L;
+
+    /**
+     * The object on which the Event initially occurred.
+     */
+    protected transient Object source;
+
+    /**
+     * Constructs a prototypical Event.
+     *
+     * @param source the object on which the Event initially occurred
+     * @throws IllegalArgumentException if source is null
+     */
+    public EventObject(Object source) {
+        if (source == null)
+            throw new IllegalArgumentException("null source");
+
+        this.source = source;
+    }
+
+    /**
+     * The object on which the Event initially occurred.
+     *
+     * @return the object on which the Event initially occurred
+     */
+    public Object getSource() {
+        return source;
+    }
+
+    /**
+     * Returns a String representation of this EventObject.
+     *
+     * @return a String representation of this EventObject
+     */
+    public String toString() {
+        return getClass().getName() + "[source=" + source + "]";
+    }
+}
diff --git a/android-35/java/util/FormatFlagsConversionMismatchException.java b/android-35/java/util/FormatFlagsConversionMismatchException.java
new file mode 100644
index 0000000..6f2464d
--- /dev/null
+++ b/android-35/java/util/FormatFlagsConversionMismatchException.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a conversion and flag are incompatible.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatFlagsConversionMismatchException
+    extends IllegalFormatException
+{
+    @java.io.Serial
+    private static final long serialVersionUID = 19120414L;
+
+    private String f;
+
+    private char c;
+
+    /**
+     * Constructs an instance of this class with the specified flag
+     * and conversion.
+     *
+     * @param  f
+     *         The flag
+     *
+     * @param  c
+     *         The conversion
+     */
+    public FormatFlagsConversionMismatchException(String f, char c) {
+        if (f == null)
+            throw new NullPointerException();
+        this.f = f;
+        this.c = c;
+    }
+
+    /**
+     * Returns the incompatible flag.
+     *
+     * @return  The flag
+     */
+     public String getFlags() {
+        return f;
+    }
+
+    /**
+     * Returns the incompatible conversion.
+     *
+     * @return  The conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    public String getMessage() {
+        return "Conversion = " + c + ", Flags = " + f;
+    }
+}
diff --git a/android-35/java/util/Formattable.java b/android-35/java/util/Formattable.java
new file mode 100644
index 0000000..2caabae
--- /dev/null
+++ b/android-35/java/util/Formattable.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+
+/**
+ * The {@code Formattable} interface must be implemented by any class that
+ * needs to perform custom formatting using the {@code 's'} conversion
+ * specifier of {@link java.util.Formatter}.  This interface allows basic
+ * control for formatting arbitrary objects.
+ *
+ * For example, the following class prints out different representations of a
+ * stock's name depending on the flags and length constraints:
+ *
+ * <pre> {@code
+ *   import java.nio.CharBuffer;
+ *   import java.util.Formatter;
+ *   import java.util.Formattable;
+ *   import java.util.Locale;
+ *   import static java.util.FormattableFlags.*;
+ *
+ *   ...
+ *
+ *   public class StockName implements Formattable {
+ *       private String symbol, companyName, frenchCompanyName;
+ *       public StockName(String symbol, String companyName,
+ *                        String frenchCompanyName) {
+ *           ...
+ *       }
+ *
+ *       ...
+ *
+ *       public void formatTo(Formatter fmt, int f, int width, int precision) {
+ *           StringBuilder sb = new StringBuilder();
+ *
+ *           // decide form of name
+ *           String name = companyName;
+ *           if (fmt.locale().equals(Locale.FRANCE))
+ *               name = frenchCompanyName;
+ *           boolean alternate = (f & ALTERNATE) == ALTERNATE;
+ *           boolean usesymbol = alternate || (precision != -1 && precision < 10);
+ *           String out = (usesymbol ? symbol : name);
+ *
+ *           // apply precision
+ *           if (precision == -1 || out.length() < precision) {
+ *               // write it all
+ *               sb.append(out);
+ *           } else {
+ *               sb.append(out.substring(0, precision - 1)).append('*');
+ *           }
+ *
+ *           // apply width and justification
+ *           int len = sb.length();
+ *           if (len < width)
+ *               for (int i = 0; i < width - len; i++)
+ *                   if ((f & LEFT_JUSTIFY) == LEFT_JUSTIFY)
+ *                       sb.append(' ');
+ *                   else
+ *                       sb.insert(0, ' ');
+ *
+ *           fmt.format(sb.toString());
+ *       }
+ *
+ *       public String toString() {
+ *           return String.format("%s - %s", symbol, companyName);
+ *       }
+ *   }
+ * }</pre>
+ *
+ * <p> When used in conjunction with the {@link java.util.Formatter}, the above
+ * class produces the following output for various format strings.
+ *
+ * <pre> {@code
+ *   Formatter fmt = new Formatter();
+ *   StockName sn = new StockName("HUGE", "Huge Fruit, Inc.",
+ *                                "Fruit Titanesque, Inc.");
+ *   fmt.format("%s", sn);                   //   -> "Huge Fruit, Inc."
+ *   fmt.format("%s", sn.toString());        //   -> "HUGE - Huge Fruit, Inc."
+ *   fmt.format("%#s", sn);                  //   -> "HUGE"
+ *   fmt.format("%-10.8s", sn);              //   -> "HUGE      "
+ *   fmt.format("%.12s", sn);                //   -> "Huge Fruit,*"
+ *   fmt.format(Locale.FRANCE, "%25s", sn);  //   -> "   Fruit Titanesque, Inc."
+ * }</pre>
+ *
+ * <p> Formattables are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and may be enforced by classes that extend and implement
+ * this interface.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to
+ * any method in this interface will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since  1.5
+ */
+public interface Formattable {
+
+    /**
+     * Formats the object using the provided {@link Formatter formatter}.
+     *
+     * @param  formatter
+     *         The {@link Formatter formatter}.  Implementing classes may call
+     *         {@link Formatter#out() formatter.out()} or {@link
+     *         Formatter#locale() formatter.locale()} to obtain the {@link
+     *         Appendable} or {@link Locale} used by this
+     *         {@code formatter} respectively.
+     *
+     * @param  flags
+     *         The flags modify the output format.  The value is interpreted as
+     *         a bitmask.  Any combination of the following flags may be set:
+     *         {@link FormattableFlags#LEFT_JUSTIFY}, {@link
+     *         FormattableFlags#UPPERCASE}, and {@link
+     *         FormattableFlags#ALTERNATE}.  If no flags are set, the default
+     *         formatting of the implementing class will apply.
+     *
+     * @param  width
+     *         The minimum number of characters to be written to the output.
+     *         If the length of the converted value is less than the
+     *         {@code width} then the output will be padded by
+     *         <code>'&nbsp;&nbsp;'</code> until the total number of characters
+     *         equals width.  The padding is at the beginning by default.  If
+     *         the {@link FormattableFlags#LEFT_JUSTIFY} flag is set then the
+     *         padding will be at the end.  If {@code width} is {@code -1}
+     *         then there is no minimum.
+     *
+     * @param  precision
+     *         The maximum number of characters to be written to the output.
+     *         The precision is applied before the width, thus the output will
+     *         be truncated to {@code precision} characters even if the
+     *         {@code width} is greater than the {@code precision}.  If
+     *         {@code precision} is {@code -1} then there is no explicit
+     *         limit on the number of characters.
+     *
+     * @throws  IllegalFormatException
+     *          If any of the parameters are invalid.  For specification of all
+     *          possible formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     */
+    void formatTo(Formatter formatter, int flags, int width, int precision);
+}
diff --git a/android-35/java/util/FormattableFlags.java b/android-35/java/util/FormattableFlags.java
new file mode 100644
index 0000000..92c020f
--- /dev/null
+++ b/android-35/java/util/FormattableFlags.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * FormattableFlags are passed to the {@link Formattable#formatTo
+ * Formattable.formatTo()} method and modify the output format for {@linkplain
+ * Formattable Formattables}.  Implementations of {@link Formattable} are
+ * responsible for interpreting and validating any flags.
+ *
+ * @since  1.5
+ */
+public class FormattableFlags {
+
+    // Explicit instantiation of this class is prohibited.
+    private FormattableFlags() {}
+
+    /**
+     * Left-justifies the output.  Spaces (<code>'&#92;u0020'</code>) will be added
+     * at the end of the converted value as required to fill the minimum width
+     * of the field.  If this flag is not set then the output will be
+     * right-justified.
+     *
+     * <p> This flag corresponds to {@code '-'} (<code>'&#92;u002d'</code>) in
+     * the format specifier.
+     */
+    public static final int LEFT_JUSTIFY = 1<<0; // '-'
+
+    /**
+     * Converts the output to upper case according to the rules of the
+     * {@linkplain java.util.Locale locale} given during creation of the
+     * {@code formatter} argument of the {@link Formattable#formatTo
+     * formatTo()} method.  The output should be equivalent the following
+     * invocation of {@link String#toUpperCase(java.util.Locale)}
+     *
+     * <pre>
+     *     out.toUpperCase() </pre>
+     *
+     * <p> This flag corresponds to {@code 'S'} (<code>'&#92;u0053'</code>) in
+     * the format specifier.
+     */
+    public static final int UPPERCASE = 1<<1;    // 'S'
+
+    /**
+     * Requires the output to use an alternate form.  The definition of the
+     * form is specified by the {@code Formattable}.
+     *
+     * <p> This flag corresponds to {@code '#'} (<code>'&#92;u0023'</code>) in
+     * the format specifier.
+     */
+    public static final int ALTERNATE = 1<<2;    // '#'
+}
diff --git a/android-35/java/util/Formatter.java b/android-35/java/util/Formatter.java
new file mode 100644
index 0000000..c968530
--- /dev/null
+++ b/android-35/java/util/Formatter.java
@@ -0,0 +1,5009 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.Flushable;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.UnsupportedTemporalTypeException;
+
+import libcore.icu.DecimalFormatData;
+import libcore.icu.LocaleData;
+import jdk.internal.math.DoubleConsts;
+import jdk.internal.math.FormattedFloatingDecimal;
+
+// Android-changed: Use localized exponent separator for %e.
+/**
+ * An interpreter for printf-style format strings.  This class provides support
+ * for layout justification and alignment, common formats for numeric, string,
+ * and date/time data, and locale-specific output.  Common Java types such as
+ * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
+ * are supported.  Limited formatting customization for arbitrary user types is
+ * provided through the {@link Formattable} interface.
+ *
+ * <p> Formatters are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and is the responsibility of users of methods in this
+ * class.
+ *
+ * <p> Formatted printing for the Java language is heavily inspired by C's
+ * {@code printf}.  Although the format strings are similar to C, some
+ * customizations have been made to accommodate the Java language and exploit
+ * some of its features.  Also, Java formatting is more strict than C's; for
+ * example, if a conversion is incompatible with a flag, an exception will be
+ * thrown.  In C inapplicable flags are silently ignored.  The format strings
+ * are thus intended to be recognizable to C programmers but not necessarily
+ * completely compatible with those in C.
+ *
+ * <p> Examples of expected usage:
+ *
+ * <blockquote><pre>
+ *   StringBuilder sb = new StringBuilder();
+ *   // Send all output to the Appendable object sb
+ *   Formatter formatter = new Formatter(sb, Locale.US);
+ *
+ *   // Explicit argument indices may be used to re-order output.
+ *   formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
+ *   // -&gt; " d  c  b  a"
+ *
+ *   // Optional locale as the first argument can be used to get
+ *   // locale-specific formatting of numbers.  The precision and width can be
+ *   // given to round and align the value.
+ *   formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
+ *   // -&gt; "e =    +2,7183"
+ *
+ *   // The '(' numeric flag may be used to format negative numbers with
+ *   // parentheses rather than a minus sign.  Group separators are
+ *   // automatically inserted.
+ *   formatter.format("Amount gained or lost since last statement: $ %(,.2f",
+ *                    balanceDelta);
+ *   // -&gt; "Amount gained or lost since last statement: $ (6,217.58)"
+ * </pre></blockquote>
+ *
+ * <p> Convenience methods for common formatting requests exist as illustrated
+ * by the following invocations:
+ *
+ * <blockquote><pre>
+ *   // Writes a formatted string to System.out.
+ *   System.out.format("Local time: %tT", Calendar.getInstance());
+ *   // -&gt; "Local time: 13:34:18"
+ *
+ *   // Writes formatted output to System.err.
+ *   System.err.printf("Unable to open file '%1$s': %2$s",
+ *                     fileName, exception.getMessage());
+ *   // -&gt; "Unable to open file 'food': No such file or directory"
+ * </pre></blockquote>
+ *
+ * <p> Like C's {@code sprintf(3)}, Strings may be formatted using the static
+ * method {@link String#format(String,Object...) String.format}:
+ *
+ * <blockquote><pre>
+ *   // Format a string containing a date.
+ *   import java.util.Calendar;
+ *   import java.util.GregorianCalendar;
+ *   import static java.util.Calendar.*;
+ *
+ *   Calendar c = new GregorianCalendar(1995, MAY, 23);
+ *   String s = String.format("Duke's Birthday: %1$tb %1$te, %1$tY", c);
+ *   // -&gt; s == "Duke's Birthday: May 23, 1995"
+ * </pre></blockquote>
+ *
+ * <h2><a id="org">Organization</a></h2>
+ *
+ * <p> This specification is divided into two sections.  The first section, <a
+ * href="#summary">Summary</a>, covers the basic formatting concepts.  This
+ * section is intended for users who want to get started quickly and are
+ * familiar with formatted printing in other programming languages.  The second
+ * section, <a href="#detail">Details</a>, covers the specific implementation
+ * details.  It is intended for users who want more precise specification of
+ * formatting behavior.
+ *
+ * <h2><a id="summary">Summary</a></h2>
+ *
+ * <p> This section is intended to provide a brief overview of formatting
+ * concepts.  For precise behavioral details, refer to the <a
+ * href="#detail">Details</a> section.
+ *
+ * <h3><a id="syntax">Format String Syntax</a></h3>
+ *
+ * <p> Every method which produces formatted output requires a <i>format
+ * string</i> and an <i>argument list</i>.  The format string is a {@link
+ * String} which may contain fixed text and one or more embedded <i>format
+ * specifiers</i>.  Consider the following example:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ * </pre></blockquote>
+ *
+ * This format string is the first argument to the {@code format} method.  It
+ * contains three format specifiers "{@code %1$tm}", "{@code %1$te}", and
+ * "{@code %1$tY}" which indicate how the arguments should be processed and
+ * where they should be inserted in the text.  The remaining portions of the
+ * format string are fixed text including {@code "Dukes Birthday: "} and any
+ * other spaces or punctuation.
+ *
+ * The argument list consists of all arguments passed to the method after the
+ * format string.  In the above example, the argument list is of size one and
+ * consists of the {@link java.util.Calendar Calendar} object {@code c}.
+ *
+ * <ul>
+ *
+ * <li> The format specifiers for general, character, and numeric types have
+ * the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width][.precision]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i> is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> The optional <i>flags</i> is a set of characters that modify the output
+ * format.  The set of valid flags depends on the conversion.
+ *
+ * <p> The optional <i>width</i> is a positive decimal integer indicating
+ * the minimum number of characters to be written to the output.
+ *
+ * <p> The optional <i>precision</i> is a non-negative decimal integer usually
+ * used to restrict the number of characters.  The specific behavior depends on
+ * the conversion.
+ *
+ * <p> The required <i>conversion</i> is a character indicating how the
+ * argument should be formatted.  The set of valid conversions for a given
+ * argument depends on the argument's data type.
+ *
+ * <li> The format specifiers for types which are used to represents dates and
+ * times have the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i>, <i>flags</i> and <i>width</i> are
+ * defined as above.
+ *
+ * <p> The required <i>conversion</i> is a two character sequence.  The first
+ * character is {@code 't'} or {@code 'T'}.  The second character indicates
+ * the format to be used.  These characters are similar to but not completely
+ * identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.
+ *
+ * <li> The format specifiers which do not correspond to arguments have the
+ * following syntax:
+ *
+ * <blockquote><pre>
+ *   %[flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>flags</i> and <i>width</i> is defined as above.
+ *
+ * <p> The required <i>conversion</i> is a character indicating content to be
+ * inserted in the output.
+ *
+ * </ul>
+ *
+ * <h3> Conversions </h3>
+ *
+ * <p> Conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <b>General</b> - may be applied to any argument
+ * type
+ *
+ * <li> <b>Character</b> - may be applied to basic types which represent
+ * Unicode characters: {@code char}, {@link Character}, {@code byte}, {@link
+ * Byte}, {@code short}, and {@link Short}. This conversion may also be
+ * applied to the types {@code int} and {@link Integer} when {@link
+ * Character#isValidCodePoint} returns {@code true}
+ *
+ * <li> <b>Numeric</b>
+ *
+ * <ol>
+ *
+ * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
+ * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
+ * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
+ * BigInteger} (but not {@code char} or {@link Character})
+ *
+ * <li><b>Floating Point</b> - may be applied to Java floating-point types:
+ * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
+ * java.math.BigDecimal BigDecimal}
+ *
+ * </ol>
+ *
+ * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
+ * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
+ * {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <li> <b>Percent</b> - produces a literal {@code '%'}
+ * (<code>'&#92;u0025'</code>)
+ *
+ * <li> <b>Line Separator</b> - produces the platform-specific line separator
+ *
+ * </ol>
+ *
+ * <p> For category <i>General</i>, <i>Character</i>, <i>Numeric</i>,
+ * <i>Integral</i> and <i>Date/Time</i> conversion, unless otherwise specified,
+ * if the argument <i>arg</i> is {@code null}, then the result is "{@code null}".
+ *
+ * <p> The following table summarizes the supported conversions.  Conversions
+ * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
+ * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
+ * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
+ * lower-case conversion characters except that the result is converted to
+ * upper case according to the rules of the prevailing {@link java.util.Locale
+ * Locale}. If there is no explicit locale specified, either at the
+ * construction of the instance or as a parameter to its method
+ * invocation, then the {@link java.util.Locale.Category#FORMAT default locale}
+ * is used.
+ *
+ *
+ * <table class="striped">
+ * <caption style="display:none">genConv</caption>
+ * <thead>
+ * <tr><th scope="col" style="vertical-align:bottom"> Conversion
+ *     <th scope="col" style="vertical-align:bottom"> Argument Category
+ *     <th scope="col" style="vertical-align:bottom"> Description
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'b'}, {@code 'B'}
+ *     <td style="vertical-align:top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code false}".  If <i>arg</i> is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf(arg)}.  Otherwise, the result is
+ *     "true".
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'h'}, {@code 'H'}
+ *     <td style="vertical-align:top"> general
+ *     <td> The result is obtained by invoking
+ *     {@code Integer.toHexString(arg.hashCode())}.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 's'}, {@code 'S'}
+ *     <td style="vertical-align:top"> general
+ *     <td> If <i>arg</i> implements {@link Formattable}, then
+ *     {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the
+ *     result is obtained by invoking {@code arg.toString()}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'c'}, {@code 'C'}
+ *     <td style="vertical-align:top"> character
+ *     <td> The result is a Unicode character
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'd'}
+ *     <td style="vertical-align:top"> integral
+ *     <td> The result is formatted as a decimal integer
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'o'}
+ *     <td style="vertical-align:top"> integral
+ *     <td> The result is formatted as an octal integer
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'x'}, {@code 'X'}
+ *     <td style="vertical-align:top"> integral
+ *     <td> The result is formatted as a hexadecimal integer
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'e'}, {@code 'E'}
+ *     <td style="vertical-align:top"> floating point
+ *     <td> The result is formatted as a decimal number in computerized
+ *     scientific notation
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'f'}
+ *     <td style="vertical-align:top"> floating point
+ *     <td> The result is formatted as a decimal number
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'g'}, {@code 'G'}
+ *     <td style="vertical-align:top"> floating point
+ *     <td> The result is formatted using computerized scientific notation or
+ *     decimal format, depending on the precision and the value after rounding.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'a'}, {@code 'A'}
+ *     <td style="vertical-align:top"> floating point
+ *     <td> The result is formatted as a hexadecimal floating-point number with
+ *     a significand and an exponent. This conversion is <b>not</b> supported
+ *     for the {@code BigDecimal} type despite the latter's being in the
+ *     <i>floating point</i> argument category.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 't'}, {@code 'T'}
+ *     <td style="vertical-align:top"> date/time
+ *     <td> Prefix for date and time conversion characters.  See <a
+ *     href="#dt">Date/Time Conversions</a>.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code '%'}
+ *     <td style="vertical-align:top"> percent
+ *     <td> The result is a literal {@code '%'} (<code>'&#92;u0025'</code>)
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'n'}
+ *     <td style="vertical-align:top"> line separator
+ *     <td> The result is the platform-specific line separator
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as conversions are illegal and are
+ * reserved for future extensions.
+ *
+ * <h3><a id="dt">Date/Time Conversions</a></h3>
+ *
+ * <p> The following date and time conversion suffix characters are defined for
+ * the {@code 't'} and {@code 'T'} conversions.  The types are similar to but
+ * not completely identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.  Additional conversion types are provided to access
+ * Java-specific functionality (e.g. {@code 'L'} for milliseconds within the
+ * second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table class="striped">
+ * <caption style="display:none">time</caption>
+ * <tbody>
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'H'}
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'I'}
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'k'}
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'l'}
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'M'}
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'S'}
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'L'}
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'N'}
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'p'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion
+ *     prefix {@code 'T'} forces this output to upper case.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'z'}
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Z'}
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the  time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 's'}
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Q'}
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table class="striped">
+ * <caption style="display:none">date</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'B'}
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'b'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'h'}
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'A'}
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'a'}
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'C'}
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Y'}
+ *     <td> Year, formatted as at least four digits with leading zeros as
+ *     necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian
+ *     calendar.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'y'}
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'j'}
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'm'}
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'd'}
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'e'}
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table class="striped">
+ * <caption style="display:none">composites</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'R'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'T'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'r'}
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}.
+ *     The location of the morning or afternoon marker ({@code '%Tp'}) may be
+ *     locale-dependent.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'D'}
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'F'}
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'c'}
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as date/time conversion suffixes
+ * are illegal and are reserved for future extensions.
+ *
+ * <h3> Flags </h3>
+ *
+ * <p> The following table summarizes the supported flags.  <i>y</i> means the
+ * flag is supported for the indicated argument types.
+ *
+ * <table class="striped">
+ * <caption style="display:none">genConv</caption>
+ * <thead>
+ * <tr><th scope="col" style="vertical-align:bottom"> Flag <th scope="col" style="vertical-align:bottom"> General
+ *     <th scope="col" style="vertical-align:bottom"> Character <th scope="col" style="vertical-align:bottom"> Integral
+ *     <th scope="col" style="vertical-align:bottom"> Floating Point
+ *     <th scope="col" style="vertical-align:bottom"> Date/Time
+ *     <th scope="col" style="vertical-align:bottom"> Description
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row"> '-' <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td> The result will be left-justified.
+ *
+ * <tr><th scope="row"> '#' <td style="text-align:center; vertical-align:top"> y<sup>1</sup>
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y<sup>3</sup>
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td> The result should use a conversion-dependent alternate form
+ *
+ * <tr><th scope="row"> '+' <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y<sup>4</sup>
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td> The result will always include a sign
+ *
+ * <tr><th scope="row"> '&nbsp;&nbsp;' <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y<sup>4</sup>
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td> The result will include a leading space for positive values
+ *
+ * <tr><th scope="row"> '0' <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> y
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td> The result will be zero-padded
+ *
+ * <tr><th scope="row"> ',' <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y<sup>2</sup>
+ *     <td style="text-align:center; vertical-align:top"> y<sup>5</sup>
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td> The result will include locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators}
+ *
+ * <tr><th scope="row"> '(' <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> -
+ *     <td style="text-align:center; vertical-align:top"> y<sup>4</sup>
+ *     <td style="text-align:center; vertical-align:top"> y<sup>5</sup>
+ *     <td style="text-align:center"> -
+ *     <td> The result will enclose negative numbers in parentheses
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> <sup>1</sup> Depends on the definition of {@link Formattable}.
+ *
+ * <p> <sup>2</sup> For {@code 'd'} conversion only.
+ *
+ * <p> <sup>3</sup> For {@code 'o'}, {@code 'x'}, and {@code 'X'}
+ * conversions only.
+ *
+ * <p> <sup>4</sup> For {@code 'd'}, {@code 'o'}, {@code 'x'}, and
+ * {@code 'X'} conversions applied to {@link java.math.BigInteger BigInteger}
+ * or {@code 'd'} applied to {@code byte}, {@link Byte}, {@code short}, {@link
+ * Short}, {@code int} and {@link Integer}, {@code long}, and {@link Long}.
+ *
+ * <p> <sup>5</sup> For {@code 'e'}, {@code 'E'}, {@code 'f'},
+ * {@code 'g'}, and {@code 'G'} conversions only.
+ *
+ * <p> Any characters not explicitly defined as flags are illegal and are
+ * reserved for future extensions.
+ *
+ * <h3> Width </h3>
+ *
+ * <p> The width is the minimum number of characters to be written to the
+ * output.  For the line separator conversion, width is not applicable; if it
+ * is provided, an exception will be thrown.
+ *
+ * <h3> Precision </h3>
+ *
+ * <p> For general argument types, the precision is the maximum number of
+ * characters to be written to the output.
+ *
+ * <p> For the floating-point conversions {@code 'a'}, {@code 'A'}, {@code 'e'},
+ * {@code 'E'}, and {@code 'f'} the precision is the number of digits after the
+ * radix point.  If the conversion is {@code 'g'} or {@code 'G'}, then the
+ * precision is the total number of digits in the resulting magnitude after
+ * rounding.
+ *
+ * <p> For character, integral, and date/time argument types and the percent
+ * and line separator conversions, the precision is not applicable; if a
+ * precision is provided, an exception will be thrown.
+ *
+ * <h3> Argument Index </h3>
+ *
+ * <p> The argument index is a decimal integer indicating the position of the
+ * argument in the argument list.  The first argument is referenced by
+ * "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> Another way to reference arguments by position is to use the
+ * {@code '<'} (<code>'&#92;u003c'</code>) flag, which causes the argument for
+ * the previous format specifier to be re-used.  For example, the following two
+ * statements would produce identical strings:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ *
+ *   String s2 = String.format("Duke's Birthday: %1$tm %&lt;te,%&lt;tY", c);
+ * </pre></blockquote>
+ *
+ * <hr>
+ * <h2><a id="detail">Details</a></h2>
+ *
+ * <p> This section is intended to provide behavioral details for formatting,
+ * including conditions and exceptions, supported data types, localization, and
+ * interactions between flags, conversions, and data types.  For an overview of
+ * formatting concepts, refer to the <a href="#summary">Summary</a>
+ *
+ * <p> Any characters not explicitly defined as conversions, date/time
+ * conversion suffixes, or flags are illegal and are reserved for
+ * future extensions.  Use of such a character in a format string will
+ * cause an {@link UnknownFormatConversionException} or {@link
+ * UnknownFormatFlagsException} to be thrown.
+ *
+ * <p> If the format specifier contains a width or precision with an invalid
+ * value or which is otherwise unsupported, then a {@link
+ * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
+ * respectively will be thrown. Similarly, values of zero for an argument
+ * index will result in an {@link IllegalFormatException}.
+ *
+ * <p> If a format specifier contains a conversion character that is not
+ * applicable to the corresponding argument, then an {@link
+ * IllegalFormatConversionException} will be thrown.
+ *
+ * <p> Values of <i>precision</i> must be in the range zero to
+ * {@link Integer#MAX_VALUE}, inclusive, otherwise
+ * {@link IllegalFormatPrecisionException} is thrown.</p>
+ *
+ * <p> Values of <i>width</i> must be in the range one to
+ * {@link Integer#MAX_VALUE}, inclusive, otherwise
+ * {@link IllegalFormatWidthException} will be thrown
+ * Note that widths can appear to have a negative value, but the negative sign
+ * is a <i>flag</i>. For example in the format string {@code "%-20s"} the
+ * <i>width</i> is <i>20</i> and the <i>flag</i> is "-".</p>
+ *
+ * <p> Values of <i>index</i> must be in the range one to
+ * {@link Integer#MAX_VALUE}, inclusive, otherwise
+ * {@link IllegalFormatException} will be thrown.</p>
+ *
+ * <p> All specified exceptions may be thrown by any of the {@code format}
+ * methods of {@code Formatter} as well as by any {@code format} convenience
+ * methods such as {@link String#format(String,Object...) String.format} and
+ * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}.
+ *
+ * <p> For category <i>General</i>, <i>Character</i>, <i>Numeric</i>,
+ * <i>Integral</i> and <i>Date/Time</i> conversion, unless otherwise specified,
+ * if the argument <i>arg</i> is {@code null}, then the result is "{@code null}".
+ *
+ * <p> Conversions denoted by an upper-case character (i.e. {@code 'B'},
+ * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'},
+ * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the
+ * corresponding lower-case conversion characters except that the result is
+ * converted to upper case according to the rules of the prevailing {@link
+ * java.util.Locale Locale}. If there is no explicit locale specified,
+ * either at the construction of the instance or as a parameter to its method
+ * invocation, then the {@link java.util.Locale.Category#FORMAT default locale}
+ * is used.
+ *
+ * <h3><a id="dgen">General</a></h3>
+ *
+ * <p> The following general conversions may be applied to any argument type:
+ *
+ * <table class="striped">
+ * <caption style="display:none">dgConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'b'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0062'</code>
+ *     <td> Produces either "{@code true}" or "{@code false}" as returned by
+ *     {@link Boolean#toString(boolean)}.
+ *
+ *     <p> If the argument is {@code null}, then the result is
+ *     "{@code false}".  If the argument is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf()}.  Otherwise, the result is
+ *     "{@code true}".
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'B'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0042'</code>
+ *     <td> The upper-case variant of {@code 'b'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'h'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0068'</code>
+ *     <td> Produces a string representing the hash code value of the object.
+ *
+ *     <p> The result is obtained by invoking
+ *     {@code Integer.toHexString(arg.hashCode())}.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'H'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0048'</code>
+ *     <td> The upper-case variant of {@code 'h'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 's'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0073'</code>
+ *     <td> Produces a string.
+ *
+ *     <p> If the argument implements {@link Formattable}, then
+ *     its {@link Formattable#formatTo formatTo} method is invoked.
+ *     Otherwise, the result is obtained by invoking the argument's
+ *     {@code toString()} method.
+ *
+ *     <p> If the {@code '#'} flag is given and the argument is not a {@link
+ *     Formattable}, then a {@link FormatFlagsConversionMismatchException}
+ *     will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'S'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0053'</code>
+ *     <td> The upper-case variant of {@code 's'}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following <a id="dFlags">flags</a> apply to general conversions:
+ *
+ * <table class="striped">
+ * <caption style="display:none">dFlags</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code '-'}
+ *     <td style="vertical-align:top"> <code>'&#92;u002d'</code>
+ *     <td> Left justifies the output.  Spaces (<code>'&#92;u0020'</code>) will be
+ *     added at the end of the converted value as required to fill the minimum
+ *     width of the field.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.  If this flag is not given
+ *     then the output will be right-justified.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code '#'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0023'</code>
+ *     <td> Requires the output use an alternate form.  The definition of the
+ *     form is specified by the conversion.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The <a id="genWidth">width</a> is the minimum number of characters to
+ * be written to the
+ * output.  If the length of the converted value is less than the width then
+ * the output will be padded by <code>'&nbsp;&nbsp;'</code> (<code>'&#92;u0020'</code>)
+ * until the total number of characters equals the width.  The padding is on
+ * the left by default.  If the {@code '-'} flag is given, then the padding
+ * will be on the right.  If the width is not specified then there is no
+ * minimum.
+ *
+ * <p> The precision is the maximum number of characters to be written to the
+ * output.  The precision is applied before the width, thus the output will be
+ * truncated to {@code precision} characters even if the width is greater than
+ * the precision.  If the precision is not specified then there is no explicit
+ * limit on the number of characters.
+ *
+ * <h3><a id="dchar">Character</a></h3>
+ *
+ * This conversion may be applied to {@code char} and {@link Character}.  It
+ * may also be applied to the types {@code byte}, {@link Byte},
+ * {@code short}, and {@link Short}, {@code int} and {@link Integer} when
+ * {@link Character#isValidCodePoint} returns {@code true}.  If it returns
+ * {@code false} then an {@link IllegalFormatCodePointException} will be
+ * thrown.
+ *
+ * <table class="striped">
+ * <caption style="display:none">charConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'c'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0063'</code>
+ *     <td> Formats the argument as a Unicode character as described in <a
+ *     href="../lang/Character.html#unicode">Unicode Character
+ *     Representation</a>.  This may be more than one 16-bit {@code char} in
+ *     the case where the argument represents a supplementary character.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'C'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0043'</code>
+ *     <td> The upper-case variant of {@code 'c'}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is defined as for <a href="#genWidth">General conversions</a>.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h3><a id="dnum">Numeric</a></h3>
+ *
+ * <p> Numeric conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <a href="#dnint"><b>Byte, Short, Integer, and Long</b></a>
+ *
+ * <li> <a href="#dnbint"><b>BigInteger</b></a>
+ *
+ * <li> <a href="#dndec"><b>Float and Double</b></a>
+ *
+ * <li> <a href="#dnbdec"><b>BigDecimal</b></a>
+ *
+ * </ol>
+ *
+ * <p> Numeric types will be formatted according to the following algorithm:
+ *
+ * <p><b><a id="L10nAlgorithm"> Number Localization Algorithm</a></b>
+ *
+ * <p> After digits are obtained for the integer part, fractional part, and
+ * exponent (as appropriate for the data type), the following transformation
+ * is applied:
+ *
+ * <ol>
+ *
+ * <li> Each digit character <i>d</i> in the string is replaced by a
+ * locale-specific digit computed relative to the current locale's
+ * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit}
+ * <i>z</i>; that is <i>d&nbsp;-&nbsp;</i> {@code '0'}
+ * <i>&nbsp;+&nbsp;z</i>.
+ *
+ * <li> If a decimal separator is present, a locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is
+ * substituted.
+ *
+ * <li> If the {@code ','} (<code>'&#92;u002c'</code>)
+ * <a id="L10nGroup">flag</a> is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
+ * inserted by scanning the integer part of the string from least significant
+ * to most significant digits and inserting a separator at intervals defined by
+ * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping
+ * size}.
+ *
+ * <li> If the {@code '0'} flag is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted
+ * after the sign character, if any, and before the first non-zero digit, until
+ * the length of the string is equal to the requested field width.
+ *
+ * <li> If the value is negative and the {@code '('} flag is given, then a
+ * {@code '('} (<code>'&#92;u0028'</code>) is prepended and a {@code ')'}
+ * (<code>'&#92;u0029'</code>) is appended.
+ *
+ * <li> If the value is negative (or floating-point negative zero) and
+ * {@code '('} flag is not given, then a {@code '-'} (<code>'&#92;u002d'</code>)
+ * is prepended.
+ *
+ * <li> If the {@code '+'} flag is given and the value is positive or zero (or
+ * floating-point positive zero), then a {@code '+'} (<code>'&#92;u002b'</code>)
+ * will be prepended.
+ *
+ * </ol>
+ *
+ * <p> If the value is NaN or positive infinity the literal strings "NaN" or
+ * "Infinity" respectively, will be output.  If the value is negative infinity,
+ * then the output will be "(Infinity)" if the {@code '('} flag is given
+ * otherwise the output will be "-Infinity".  These values are not localized.
+ *
+ * <p><a id="dnint"><b> Byte, Short, Integer, and Long </b></a>
+ *
+ * <p> The following conversions may be applied to {@code byte}, {@link Byte},
+ * {@code short}, {@link Short}, {@code int} and {@link Integer},
+ * {@code long}, and {@link Long}.
+ *
+ * <table class="striped">
+ * <caption style="display:none">IntConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'd'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0064'</code>
+ *     <td> Formats the argument as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '0'} flag is given and the value is negative, then
+ *     the zero padding will occur after the sign.
+ *
+ *     <p> If the {@code '#'} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'o'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006f'</code>
+ *     <td> Formats the argument as an integer in base eight.  No localization
+ *     is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code '0'}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If {@code '('}, {@code '+'}, '&nbsp;&nbsp;', or {@code ','} flags
+ *     are given then a {@link FormatFlagsConversionMismatchException} will be
+ *     thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'x'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0078'</code>
+ *     <td> Formats the argument as an integer in base sixteen. No
+ *     localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If {@code '('}, <code>'&nbsp;&nbsp;'</code>, {@code '+'}, or
+ *     {@code ','} flags are given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'X'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0058'</code>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<code>'&#92;u0061'</code> -  <code>'&#92;u0066'</code>).
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the radix indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> The following <a id="intFlags">flags</a> apply to numeric integral
+ * conversions:
+ *
+ * <table class="striped">
+ * <caption style="display:none">intFlags</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code '+'}
+ *     <td style="vertical-align:top"> <code>'&#92;u002b'</code>
+ *     <td> Requires the output to include a positive sign for all positive
+ *     numbers.  If this flag is not given then only negative values will
+ *     include a sign.
+ *
+ *     <p> If both the {@code '+'} and <code>'&nbsp;&nbsp;'</code> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> <code>'&nbsp;&nbsp;'</code>
+ *     <td style="vertical-align:top"> <code>'&#92;u0020'</code>
+ *     <td> Requires the output to include a single extra space
+ *     (<code>'&#92;u0020'</code>) for non-negative values.
+ *
+ *     <p> If both the {@code '+'} and <code>'&nbsp;&nbsp;'</code> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code '0'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0030'</code>
+ *     <td> Requires the output to be padded with leading {@linkplain
+ *     java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field
+ *     width following any sign or radix indicator except when converting NaN
+ *     or infinity.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.
+ *
+ *     <p> If both the {@code '-'} and {@code '0'} flags are given then an
+ *     {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code ','}
+ *     <td style="vertical-align:top"> <code>'&#92;u002c'</code>
+ *     <td> Requires the output to include the locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
+ *     described in the <a href="#L10nGroup">"group" section</a> of the
+ *     localization algorithm.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code '('}
+ *     <td style="vertical-align:top"> <code>'&#92;u0028'</code>
+ *     <td> Requires the output to prepend a {@code '('}
+ *     (<code>'&#92;u0028'</code>) and append a {@code ')'}
+ *     (<code>'&#92;u0029'</code>) to negative values.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> If no <a id="intdFlags">flags</a> are given the default formatting is
+ * as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'} (<code>'&#92;u002d'</code>)
+ *
+ * <li> Positive numbers and zero do not include a sign or extra leading
+ * space
+ *
+ * <li> No grouping separators are included
+ *
+ * </ul>
+ *
+ * <p> The <a id="intWidth">width</a> is the minimum number of characters to
+ * be written to the output.  This includes any signs, digits, grouping
+ * separators, radix indicator, and parentheses.  If the length of the
+ * converted value is less than the width then the output will be padded by
+ * spaces (<code>'&#92;u0020'</code>) until the total number of characters equals
+ * width.  The padding is on the left by default.  If {@code '-'} flag is
+ * given then the padding will be on the right.  If width is not specified then
+ * there is no minimum.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a id="dnbint"><b> BigInteger </b></a>
+ *
+ * <p> The following conversions may be applied to {@link
+ * java.math.BigInteger}.
+ *
+ * <table class="striped">
+ * <caption style="display:none">bIntConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'd'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0064'</code>
+ *     <td> Requires the output to be formatted as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '#'} flag is given {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'o'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006f'</code>
+ *     <td> Requires the output to be formatted as an integer in base eight.
+ *     No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<code>'&#92;u002d'</code>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<code>'&#92;u002b'</code>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with {@code '0'} prefix.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'x'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0078'</code>
+ *     <td> Requires the output to be formatted as an integer in base
+ *     sixteen.  No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<code>'&#92;u002d'</code>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<code>'&#92;u002b'</code>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'X'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0058'</code>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<code>'&#92;u0061'</code> - <code>'&#92;u0066'</code>).
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the base indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '0'} flag is given and the value is negative, then the
+ * zero padding will occur after the sign.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.  The <a href="#intdFlags">default behavior</a> when no flags are
+ * given is the same as for Byte, Short, Integer, and Long.
+ *
+ * <p> The specification of <a href="#intWidth">width</a> is the same as
+ * defined for Byte, Short, Integer, and Long.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a id="dndec"><b> Float and Double</b></a>
+ *
+ * <p> The following conversions may be applied to {@code float}, {@link
+ * Float}, {@code double} and {@link Double}.
+ *
+ * <table class="striped">
+ * <caption style="display:none">floatConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'e'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0065'</code>
+ *     <td> Requires the output to be formatted using <a
+ *     id="scientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the lower-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'e'}), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.RoundingMode#HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ *     <p>If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'E'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0045'</code>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be the upper-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'E'}).
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'g'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0067'</code>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#decimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#scientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'G'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0047'</code>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'f'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0066'</code>
+ *     <td> Requires the output to be formatted using <a id="decimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> If <i>m</i> NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.RoundingMode#HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'a'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0061'</code>
+ *     <td> Requires the output to be formatted in hexadecimal exponential
+ *     form.  No localization is applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument <i>x</i>.
+ *
+ *     <p> If <i>x</i> is negative or a negative-zero value then the result
+ *     will begin with {@code '-'} (<code>'&#92;u002d'</code>).
+ *
+ *     <p> If <i>x</i> is positive or a positive-zero value and the
+ *     {@code '+'} flag is given then the result will begin with {@code '+'}
+ *     (<code>'&#92;u002b'</code>).
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <ul>
+ *
+ *     <li> If the value is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.
+ *
+ *     <li> If <i>m</i> is zero then it is represented by the string
+ *     {@code "0x0.0p0"}.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a normalized
+ *     representation then substrings are used to represent the significand and
+ *     exponent fields.  The significand is represented by the characters
+ *     {@code "0x1."} followed by the hexadecimal representation of the rest
+ *     of the significand as a fraction.  The exponent is represented by
+ *     {@code 'p'} (<code>'&#92;u0070'</code>) followed by a decimal string of the
+ *     unbiased exponent as if produced by invoking {@link
+ *     Integer#toString(int) Integer.toString} on the exponent value.  If the
+ *     precision is specified, the value is rounded to the given number of
+ *     hexadecimal digits.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a subnormal
+ *     representation then, unless the precision is specified to be in the range
+ *     1 through 12, inclusive, the significand is represented by the characters
+ *     {@code '0x0.'} followed by the hexadecimal representation of the rest of
+ *     the significand as a fraction, and the exponent represented by
+ *     {@code 'p-1022'}.  If the precision is in the interval
+ *     [1,&nbsp;12], the subnormal value is normalized such that it
+ *     begins with the characters {@code '0x1.'}, rounded to the number of
+ *     hexadecimal digits of precision, and the exponent adjusted
+ *     accordingly.  Note that there must be at least one nonzero digit in a
+ *     subnormal significand.
+ *
+ *     </ul>
+ *
+ *     <p> If the {@code '('} or {@code ','} flags are given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'A'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0041'</code>
+ *     <td> The upper-case variant of {@code 'a'}.  The entire string
+ *     representing the number will be converted to upper case including the
+ *     {@code 'x'} (<code>'&#92;u0078'</code>) and {@code 'p'}
+ *     (<code>'&#92;u0070'</code> and all hexadecimal digits {@code 'a'} -
+ *     {@code 'f'} (<code>'&#92;u0061'</code> - <code>'&#92;u0066'</code>).
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> If no <a id="floatdFlags">flags</a> are given the default formatting
+ * is as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'}
+ *
+ * <li> Positive numbers and positive zero do not include a sign or extra
+ * leading space
+ *
+ * <li> No grouping separators are included
+ *
+ * <li> The decimal separator will only appear if a digit follows it
+ *
+ * </ul>
+ *
+ * <p> The <a id="floatDWidth">width</a> is the minimum number of characters
+ * to be written to the output.  This includes any signs, digits, grouping
+ * separators, decimal separators, exponential symbol, radix indicator,
+ * parentheses, and strings representing infinity and NaN as applicable.  If
+ * the length of the converted value is less than the width then the output
+ * will be padded by spaces (<code>'&#92;u0020'</code>) until the total number of
+ * characters equals width.  The padding is on the left by default.  If the
+ * {@code '-'} flag is given then the padding will be on the right.  If width
+ * is not specified then there is no minimum.
+ *
+ * <p> If the <a id="floatDPrec">conversion</a> is {@code 'e'},
+ * {@code 'E'} or {@code 'f'}, then the precision is the number of digits
+ * after the decimal separator.  If the precision is not specified, then it is
+ * assumed to be {@code 6}.
+ *
+ * <p> If the conversion is {@code 'g'} or {@code 'G'}, then the precision is
+ * the total number of significant digits in the resulting magnitude after
+ * rounding.  If the precision is not specified, then the default value is
+ * {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ * {@code 1}.
+ *
+ * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision
+ * is the number of hexadecimal digits after the radix point.  If the
+ * precision is not provided, then all of the digits as returned by {@link
+ * Double#toHexString(double)} will be output.
+ *
+ * <p><a id="dnbdec"><b> BigDecimal </b></a>
+ *
+ * <p> The following conversions may be applied {@link java.math.BigDecimal
+ * BigDecimal}.
+ *
+ * <table class="striped">
+ * <caption style="display:none">floatConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'e'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0065'</code>
+ *     <td> Requires the output to be formatted using <a
+ *     id="bscientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the exponent symbol {@code 'e'}
+ *     (<code>'&#92;u0065'</code>), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point then
+ *     the value will be rounded using the
+ *     {@linkplain java.math.RoundingMode#HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ *     <p> If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'E'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0045'</code>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be {@code 'E'} (<code>'&#92;u0045'</code>).
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'g'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0067'</code>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#bdecimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#bscientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'G'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0047'</code>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'f'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0066'</code>
+ *     <td> Requires the output to be formatted using <a id="bdecimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point
+ *     then the value will be rounded using the
+ *     {@linkplain java.math.RoundingMode#HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
+ * given is the same as for Float and Double.
+ *
+ * <p> The specification of <a href="#floatDWidth">width</a> and <a
+ * href="#floatDPrec">precision</a> is the same as defined for Float and
+ * Double.
+ *
+ * <h3><a id="ddt">Date/Time</a></h3>
+ *
+ * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
+ * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <table class="striped">
+ * <caption style="display:none">DTConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 't'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0074'</code>
+ *     <td> Prefix for date and time conversion characters.
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'T'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0054'</code>
+ *     <td> The upper-case variant of {@code 't'}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following date and time conversion character suffixes are defined
+ * for the {@code 't'} and {@code 'T'} conversions.  The types are similar to
+ * but not completely identical to those defined by GNU {@code date} and
+ * POSIX {@code strftime(3c)}.  Additional conversion types are provided to
+ * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
+ * within the second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table class="striped">
+ * <caption style="display:none">time</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top"> {@code 'H'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0048'</code>
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}. {@code 00}
+ *     corresponds to midnight.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'I'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0049'</code>
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.  {@code 01} corresponds to
+ *     one o'clock (either morning or afternoon).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'k'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006b'</code>
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *     {@code 0} corresponds to midnight.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'l'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006c'</code>
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.  {@code 1}
+ *     corresponds to one o'clock (either morning or afternoon).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'M'}
+ *     <td style="vertical-align:top"> <code>'&#92;u004d'</code>
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'S'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0053'</code>
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'L'}
+ *     <td style="vertical-align:top"> <code>'&#92;u004c'</code>
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'N'}
+ *     <td style="vertical-align:top"> <code>'&#92;u004e'</code>
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.  The precision
+ *     of this value is limited by the resolution of the underlying operating
+ *     system or hardware.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'p'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0070'</code>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}".  Use of the
+ *     conversion prefix {@code 'T'} forces this output to upper case.  (Note
+ *     that {@code 'p'} produces lower-case output.  This is different from
+ *     GNU {@code date} and POSIX {@code strftime(3c)} which produce
+ *     upper-case output.)
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'z'}
+ *     <td style="vertical-align:top"> <code>'&#92;u007a'</code>
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Z'}
+ *     <td style="vertical-align:top"> <code>'&#92;u005a'</code>
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 's'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0073'</code>
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Q'}
+ *     <td style="vertical-align:top"> <code>'&#92;u004f'</code>
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}. The precision of this value is limited by
+ *     the resolution of the underlying operating system or hardware.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table class="striped">
+ * <caption style="display:none">date</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'B'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0042'</code>
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'b'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0062'</code>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'h'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0068'</code>
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'A'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0041'</code>
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'a'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0061'</code>
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'C'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0043'</code>
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'Y'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0059'</code> <td> Year, formatted to at least
+ *     four digits with leading zeros as necessary, e.g. {@code 0092} equals
+ *     {@code 92} CE for the Gregorian calendar.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'y'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0079'</code>
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'j'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006a'</code>
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *     {@code 001} corresponds to the first day of the year.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'm'}
+ *     <td style="vertical-align:top"> <code>'&#92;u006d'</code>
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the
+ *     year and ("{@code 13}" is a special value required to support lunar
+ *     calendars).
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'd'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0064'</code>
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day
+ *     of the month.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'e'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0065'</code>
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31} where
+ *     "{@code 1}" is the first day of the month.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table class="striped">
+ * <caption style="display:none">composites</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'R'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0052'</code>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'T'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0054'</code>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'r'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0072'</code>
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS
+ *     %Tp"}.  The location of the morning or afternoon marker
+ *     ({@code '%Tp'}) may be locale-dependent.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'D'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0044'</code>
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'F'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0046'</code>
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'c'}
+ *     <td style="vertical-align:top"> <code>'&#92;u0063'</code>
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output.  If the length of the converted value is less than
+ * the {@code width} then the output will be padded by spaces
+ * (<code>'&#92;u0020'</code>) until the total number of characters equals width.
+ * The padding is on the left by default.  If the {@code '-'} flag is given
+ * then the padding will be on the right.  If width is not specified then there
+ * is no minimum.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h3><a id="dper">Percent</a></h3>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table class="striped">
+ * <caption style="display:none">DTConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code '%'}
+ *     <td> The result is a literal {@code '%'} (<code>'&#92;u0025'</code>)
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output including the {@code '%'}.  If the length of the
+ * converted value is less than the {@code width} then the output will be
+ * padded by spaces (<code>'&#92;u0020'</code>) until the total number of
+ * characters equals width.  The padding is on the left.  If width is not
+ * specified then just the {@code '%'} is output.
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If any other flags are provided, then a
+ * {@link IllegalFormatFlagsException } will be thrown.
+ *
+ * <p> The precision is not applicable.  If the precision is specified an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <h3><a id="dls">Line Separator</a></h3>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table class="striped">
+ * <caption style="display:none">DTConv</caption>
+ * <tbody>
+ *
+ * <tr><th scope="row" style="vertical-align:top">{@code 'n'}
+ *     <td> the platform-specific line separator as returned by {@link
+ *     System#lineSeparator()}.
+ *
+ * </tbody>
+ * </table>
+ *
+ * <p> Flags, width, and precision are not applicable.  If any are provided an
+ * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException},
+ * and {@link IllegalFormatPrecisionException}, respectively will be thrown.
+ *
+ * <h3><a id="dpos">Argument Index</a></h3>
+ *
+ * <p> Format specifiers can reference arguments in three ways:
+ *
+ * <ul>
+ *
+ * <li> <i>Explicit indexing</i> is used when the format specifier contains an
+ * argument index.  The argument index is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.  An argument
+ * may be referenced more than once.
+ *
+ * <p> For example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s",
+ *                    "a", "b", "c", "d")
+ *   // -&gt; "d c b a d c b a"
+ * </pre></blockquote>
+ *
+ * <li> <i>Relative indexing</i> is used when the format specifier contains a
+ * {@code '<'} (<code>'&#92;u003c'</code>) flag which causes the argument for
+ * the previous format specifier to be re-used.  If there is no previous
+ * argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <blockquote><pre>
+ *    formatter.format("%s %s %&lt;s %&lt;s", "a", "b", "c", "d")
+ *    // -&gt; "a b b b"
+ *    // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <li> <i>Ordinary indexing</i> is used when the format specifier contains
+ * neither an argument index nor a {@code '<'} flag.  Each format specifier
+ * which uses ordinary indexing is assigned a sequential implicit index into
+ * argument list which is independent of the indices used by explicit or
+ * relative indexing.
+ *
+ * <blockquote><pre>
+ *   formatter.format("%s %s %s %s", "a", "b", "c", "d")
+ *   // -&gt; "a b c d"
+ * </pre></blockquote>
+ *
+ * </ul>
+ *
+ * <p> It is possible to have a format string which uses all forms of indexing,
+ * for example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%2$s %s %&lt;s %s", "a", "b", "c", "d")
+ *   // -&gt; "b a a b"
+ *   // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <p> The maximum number of arguments is limited by the maximum dimension of a
+ * Java array as defined by
+ * <cite>The Java Virtual Machine Specification</cite>.
+ * If the argument index does not correspond to an
+ * available argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <p> If there are more arguments than format specifiers, the extra arguments
+ * are ignored.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @author  Iris Clark
+ * @since 1.5
+ */
+// Android-added: errorprone crashes with NPE otherwise. See: https://github.com/google/error-prone/issues/2638
+@SuppressWarnings("FallThrough")
+public final class Formatter implements Closeable, Flushable {
+    private Appendable a;
+    private final Locale l;
+
+    private IOException lastException;
+
+    // Non-character value used to mark zero as uninitialized
+    private static final char ZERO_SENTINEL = '\uFFFE';
+    private char zero = ZERO_SENTINEL;
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
+     */
+    private static Charset toCharset(String csn)
+        throws UnsupportedEncodingException
+    {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            // UnsupportedEncodingException should be thrown
+            throw new UnsupportedEncodingException(csn);
+        }
+    }
+
+    private static final Appendable nonNullAppendable(Appendable a) {
+        if (a == null)
+            return new StringBuilder();
+
+        return a;
+    }
+
+    /* Private constructors */
+    private Formatter(Locale l, Appendable a) {
+        this.a = a;
+        this.l = l;
+    }
+
+    private Formatter(Charset charset, Locale l, File file)
+        throws FileNotFoundException
+    {
+        this(l,
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)));
+    }
+
+    /**
+     * Constructs a new formatter.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose
+     * current content may be converted into a string by invoking {@link
+     * #toString toString()}.  The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     */
+    public Formatter() {
+        this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     */
+    public Formatter(Appendable a) {
+        this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified locale.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose current
+     * content may be converted into a string by invoking {@link #toString
+     * toString()}.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Locale l) {
+        this(l, new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination and locale.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Appendable a, Locale l) {
+        this(l, nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(String fileName) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name, charset, and
+     * locale.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, new File(fileName));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name, charset, and
+     * locale.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  IOException
+     *          if an I/O error occurs while opening or creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws NullPointerException
+     *         if {@code fileName} or {@code charset} is {@code null}.
+     */
+    public Formatter(String fileName, Charset charset, Locale l) throws IOException {
+        this(Objects.requireNonNull(charset, "charset"), l, new File(fileName));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(File file) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(file, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file, charset, and
+     * locale.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, file);
+    }
+
+    /**
+     * Constructs a new formatter with the specified file, charset, and
+     * locale.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws IOException
+     *         if an I/O error occurs while opening or creating the file
+     *
+     * @throws SecurityException
+     *         If a security manager is present and {@link
+     *         SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *         write access to the file
+     *
+     * @throws NullPointerException
+     *         if {@code file} or {@code charset} is {@code null}.
+     */
+    public Formatter(File file, Charset charset, Locale l) throws IOException {
+        this(Objects.requireNonNull(charset, "charset"), l, file);
+    }
+
+
+    /**
+     * Constructs a new formatter with the specified print stream.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * <p> Characters are written to the given {@link java.io.PrintStream
+     * PrintStream} object and are therefore encoded using that object's
+     * charset.
+     *
+     * @param  ps
+     *         The stream to use as the destination of this formatter.
+     */
+    public Formatter(PrintStream ps) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             (Appendable)Objects.requireNonNull(ps));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     */
+    public Formatter(OutputStream os) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(os)));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream and
+     * charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn)
+        throws UnsupportedEncodingException
+    {
+        this(os, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream, charset,
+     * and locale.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn, Locale l)
+        throws UnsupportedEncodingException
+    {
+        this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream, charset,
+     * and locale.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  charset
+     *         A {@linkplain java.nio.charset.Charset charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws NullPointerException
+     *         if {@code os} or {@code charset} is {@code null}.
+     */
+    public Formatter(OutputStream os, Charset charset, Locale l) {
+        this(l, new BufferedWriter(new OutputStreamWriter(os, charset)));
+    }
+
+    private char zero() {
+        char zero = this.zero;
+        if (zero == ZERO_SENTINEL) {
+            if ((l != null) && !l.equals(Locale.US)) {
+                // Android-changed: Improve the performance by 10x http://b/197788756
+                // Unclear if this mapping is needed but inherited from DecimalFormatSymbols
+                DecimalFormatData decimalFormatData =
+                        DecimalFormatData.getInstance(LocaleData.mapInvalidAndNullLocales(l));
+                return decimalFormatData.getZeroDigit();
+                // DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                // zero = dfs.getZeroDigit();
+            } else {
+                zero = '0';
+            }
+            this.zero = zero;
+        }
+        return zero;
+    }
+
+    /**
+     * Returns the locale set by the construction of this formatter.
+     *
+     * <p> The {@link #format(java.util.Locale,String,Object...) format} method
+     * for this object which has a locale argument does not change this value.
+     *
+     * @return  {@code null} if no localization is applied, otherwise a
+     *          locale
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Locale locale() {
+        ensureOpen();
+        return l;
+    }
+
+    /**
+     * Returns the destination for the output.
+     *
+     * @return  The destination for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Appendable out() {
+        ensureOpen();
+        return a;
+    }
+
+    /**
+     * Returns the result of invoking {@code toString()} on the destination
+     * for the output.  For example, the following code formats text into a
+     * {@link StringBuilder} then retrieves the resultant string:
+     *
+     * <blockquote><pre>
+     *   Formatter f = new Formatter();
+     *   f.format("Last reboot at %tc", lastRebootDate);
+     *   String s = f.toString();
+     *   // -&gt; s == "Last reboot at Sat Jan 01 00:00:00 PST 2000"
+     * </pre></blockquote>
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     out().toString() </pre>
+     *
+     * <p> Depending on the specification of {@code toString} for the {@link
+     * Appendable}, the returned string may or may not contain the characters
+     * written to the destination.  For instance, buffers typically return
+     * their contents in {@code toString()}, but streams cannot since the
+     * data is discarded.
+     *
+     * @return  The result of invoking {@code toString()} on the destination
+     *          for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public String toString() {
+        ensureOpen();
+        return a.toString();
+    }
+
+    /**
+     * Flushes this formatter.  If the destination implements the {@link
+     * java.io.Flushable} interface, its {@code flush} method will be invoked.
+     *
+     * <p> Flushing a formatter writes any buffered output in the destination
+     * to the underlying stream.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public void flush() {
+        ensureOpen();
+        if (a instanceof Flushable) {
+            try {
+                ((Flushable)a).flush();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+    }
+
+    /**
+     * Closes this formatter.  If the destination implements the {@link
+     * java.io.Closeable} interface, its {@code close} method will be invoked.
+     *
+     * <p> Closing a formatter allows it to release resources it may be holding
+     * (such as open files).  If the formatter is already closed, then invoking
+     * this method has no effect.
+     *
+     * <p> Attempting to invoke any methods except {@link #ioException()} in
+     * this formatter after it has been closed will result in a {@link
+     * FormatterClosedException}.
+     */
+    public void close() {
+        if (a == null)
+            return;
+        try {
+            if (a instanceof Closeable)
+                ((Closeable)a).close();
+        } catch (IOException ioe) {
+            lastException = ioe;
+        } finally {
+            a = null;
+        }
+    }
+
+    private void ensureOpen() {
+        if (a == null)
+            throw new FormatterClosedException();
+    }
+
+    /**
+     * Returns the {@code IOException} last thrown by this formatter's {@link
+     * Appendable}.
+     *
+     * <p> If the destination's {@code append()} method never throws
+     * {@code IOException}, then this method will always return {@code null}.
+     *
+     * @return  The last exception thrown by the Appendable or {@code null} if
+     *          no such exception exists.
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified format string and arguments.  The locale used is the one
+     * defined during the construction of this formatter.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(String format, Object ... args) {
+        return format(l, format, args);
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified locale, format string, and arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.  This does not change this object's locale that was
+     *         set during construction.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(Locale l, String format, Object ... args) {
+        ensureOpen();
+
+        // index of last argument referenced
+        int last = -1;
+        // last ordinary index
+        int lasto = -1;
+
+        List<FormatString> fsa = parse(format);
+        for (int i = 0; i < fsa.size(); i++) {
+            var fs = fsa.get(i);
+            int index = fs.index();
+            try {
+                switch (index) {
+                    case -2 ->  // fixed string, "%n", or "%%"
+                        fs.print(null, l);
+                    case -1 -> {  // relative index
+                        if (last < 0 || (args != null && last > args.length - 1))
+                            throw new MissingFormatArgumentException(fs.toString());
+                        fs.print((args == null ? null : args[last]), l);
+                    }
+                    case 0 -> {  // ordinary index
+                        lasto++;
+                        last = lasto;
+                        if (args != null && lasto > args.length - 1)
+                            throw new MissingFormatArgumentException(fs.toString());
+                        fs.print((args == null ? null : args[lasto]), l);
+                    }
+                    default -> {  // explicit index
+                        last = index - 1;
+                        if (args != null && last > args.length - 1)
+                            throw new MissingFormatArgumentException(fs.toString());
+                        fs.print((args == null ? null : args[last]), l);
+                    }
+                }
+            } catch (IOException x) {
+                lastException = x;
+            }
+        }
+        return this;
+    }
+
+    // BEGIN Android-changed: changed parse() to manual parsing instead of regex.
+    /**
+     * Finds format specifiers in the format string.
+     */
+    private List<FormatString> parse(String s) {
+        ArrayList<FormatString> al = new ArrayList<>();
+        for (int i = 0, len = s.length(); i < len; ) {
+            int nextPercent = s.indexOf('%', i);
+            if (s.charAt(i) != '%') {
+                // This is plain-text part, find the maximal plain-text
+                // sequence and store it.
+                int plainTextStart = i;
+                int plainTextEnd = (nextPercent == -1) ? len: nextPercent;
+                al.add(new FixedString(s, plainTextStart, plainTextEnd));
+                i = plainTextEnd;
+            } else {
+                // We have a format specifier
+                FormatSpecifierParser fsp = new FormatSpecifierParser(s, i + 1);
+                al.add(fsp.getFormatSpecifier());
+                i = fsp.getEndIdx();
+            }
+        }
+        return al;
+    }
+
+    /**
+     * Parses the format specifier.
+     * %[argument_index$][flags][width][.precision][t]conversion
+     */
+    private class FormatSpecifierParser {
+        private final String format;
+        private int cursor;
+        private FormatSpecifier fs;
+
+        private String index;
+        private String flags;
+        private String width;
+        private String precision;
+        private String tT;
+        private String conv;
+
+        private static final String FLAGS = ",-(+# 0<";
+
+        public FormatSpecifierParser(String format, int startIdx) {
+            this.format = format;
+            cursor = startIdx;
+            // Index
+            if (nextIsInt()) {
+                String nint = nextInt();
+                if (peek() == '$') {
+                    index = nint;
+                    advance();
+                } else if (nint.charAt(0) == '0') {
+                    // This is a flag, skip to parsing flags.
+                    back(nint.length());
+                } else {
+                    // This is the width, skip to parsing precision.
+                    width = nint;
+                }
+            }
+            // Flags
+            flags = "";
+            while (width == null && FLAGS.indexOf(peek()) >= 0) {
+                flags += advance();
+            }
+            // Width
+            if (width == null && nextIsInt()) {
+                width = nextInt();
+            }
+            // Precision
+            if (peek() == '.') {
+                advance();
+                if (!nextIsInt()) {
+                    throw new IllegalFormatPrecisionException(peek());
+                }
+                precision = nextInt();
+            }
+            // tT
+            if (peek() == 't' || peek() == 'T') {
+                tT = String.valueOf(advance());
+            }
+            // Conversion
+            conv = String.valueOf(advance());
+
+            fs = new FormatSpecifier(index, flags, width, precision, tT, conv);
+        }
+
+        private String nextInt() {
+            int strBegin = cursor;
+            while (nextIsInt()) {
+                advance();
+            }
+            return format.substring(strBegin, cursor);
+        }
+
+        private boolean nextIsInt() {
+            return !isEnd() && Character.isDigit(peek());
+        }
+
+        private char peek() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor);
+        }
+
+        private char advance() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor++);
+        }
+
+        private void back(int len) {
+            cursor -= len;
+        }
+
+        private boolean isEnd() {
+            return cursor == format.length();
+        }
+
+        public FormatSpecifier getFormatSpecifier() {
+            return fs;
+        }
+
+        public int getEndIdx() {
+            return cursor;
+        }
+    }
+    // END Android-changed: changed parse() to manual parsing instead of regex.
+
+    private interface FormatString {
+        int index();
+        void print(Object arg, Locale l) throws IOException;
+        String toString();
+    }
+
+    private class FixedString implements FormatString {
+        private final String s;
+        private final int start;
+        private final int end;
+        FixedString(String s, int start, int end) {
+            this.s = s;
+            this.start = start;
+            this.end = end;
+        }
+        public int index() { return -2; }
+        public void print(Object arg, Locale l)
+            throws IOException { a.append(s, start, end); }
+        public String toString() { return s.substring(start, end); }
+    }
+
+    /**
+     * Enum for {@code BigDecimal} formatting.
+     */
+    public enum BigDecimalLayoutForm {
+        /**
+         * Format the {@code BigDecimal} in computerized scientific notation.
+         */
+        SCIENTIFIC,
+
+        /**
+         * Format the {@code BigDecimal} as a decimal number.
+         */
+        DECIMAL_FLOAT
+    };
+
+    /**
+     * Prior to Android 15 (V), validations of argument index, flags, width, and precision
+     * were lax - it was allowed to use 0 and Integer.MAX_VALUE + 1 as argument index.
+     * <p> Now it will throw exception, as documentation says. Flag is enabled on Android 15+.
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.VANILLA_ICE_CREAM)
+    public static final long ENABLE_STRICT_FORMATTER_VALIDATION = 270674727L;
+
+    private static boolean isStrictValidationEnabled() {
+        return VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM
+                && Compatibility.isChangeEnabled(ENABLE_STRICT_FORMATTER_VALIDATION);
+    }
+
+    private class FormatSpecifier implements FormatString {
+
+        private int index = 0;
+        private Flags f = Flags.NONE;
+        private int width = -1;
+        private int precision = -1;
+        private boolean dt = false;
+        private char c;
+
+        // BEGIN Android-changed: entire String is always consumed.
+        /*
+        private void index(String s, int start, int end) {
+            if (start >= 0) {
+                try {
+                    // skip the trailing '$'
+                    index = Integer.parseInt(s, start, end - 1, 10);
+                    if (index <= 0) {
+                       throw new IllegalFormatArgumentIndexException(index);
+                    }
+                } catch (NumberFormatException x) {
+                    throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE);
+                }
+            }
+        }
+        */
+        private void index(String s) {
+            if (s != null) {
+                try {
+                    // FormatSpecifierParser passes in correct String.
+                    index = Integer.parseInt(s);
+                    // Before V no exception was thrown by this method.
+                    if (isStrictValidationEnabled()) {
+                        if (index <= 0) {
+                           throw new IllegalFormatArgumentIndexException(index);
+                        }
+                    }
+                } catch (NumberFormatException x) {
+                    // And this exception was swallowed.
+                    if (isStrictValidationEnabled()) {
+                        throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE);
+                    } else {
+                        // -1 is the default value of the old implementation. index value was left
+                        // untouched in NFE case.
+                        index = -1;
+                    }
+                }
+            }
+        }
+        // END Android-changed: entire String is always consumed.
+
+        public int index() {
+            return index;
+        }
+
+        // Android-changed: entire String is always consumed.
+        // private void flags(String s, int start, int end) {
+        private void flags(String s) {
+            // f = Flags.parse(s, start, end);
+            f = Flags.parse(s, 0, s.length());
+            if (f.contains(Flags.PREVIOUS))
+                index = -1;
+        }
+
+        // Android-changed: entire String is always consumed.
+        // private void width(String s, int start, int end) {
+        private void width(String s) {
+            width = -1;
+            // if (start >= 0) {
+            if (s != null) {
+                try {
+                    // width = Integer.parseInt(s, start, end, 10);
+                    width = Integer.parseInt(s);
+                    if (width < 0)
+                        throw new IllegalFormatWidthException(width);
+                } catch (NumberFormatException x) {
+                    // Android-changed: prior to V this exception was swallowed.
+                    // throw new IllegalFormatWidthException(Integer.MIN_VALUE);
+                    if (isStrictValidationEnabled()) {
+                        throw new IllegalFormatWidthException(Integer.MIN_VALUE);
+                    }
+                }
+            }
+        }
+
+        // Android-changed: entire String is always consumed.
+        // private void precision(String s, int start, int end) {
+        private void precision(String s) {
+            precision = -1;
+            // if (start >= 0) {
+            if (s != null) {
+                try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // skip the leading '.'
+                    // precision = Integer.parseInt(s, start + 1, end, 10);
+                    precision = Integer.parseInt(s);
+                    if (precision < 0)
+                        throw new IllegalFormatPrecisionException(precision);
+                } catch (NumberFormatException x) {
+                    // Android-changed: prior to V this exception was swallowed.
+                    // throw new IllegalFormatPrecisionException(Integer.MIN_VALUE);
+                    if (isStrictValidationEnabled()) {
+                        throw new IllegalFormatPrecisionException(Integer.MIN_VALUE);
+                    }
+                }
+            }
+        }
+
+        private void conversion(char conv) {
+            c = conv;
+            if (!dt) {
+                if (!Conversion.isValid(c)) {
+                    throw new UnknownFormatConversionException(String.valueOf(c));
+                }
+                if (Character.isUpperCase(c)) {
+                    f.add(Flags.UPPERCASE);
+                    c = Character.toLowerCase(c);
+                }
+                if (Conversion.isText(c)) {
+                    index = -2;
+                }
+            }
+        }
+
+        FormatSpecifier(char conv) {
+            c = conv;
+            if (Character.isUpperCase(conv)) {
+                f = Flags.UPPERCASE;
+                c = Character.toLowerCase(conv);
+            }
+            if (Conversion.isText(conv)) {
+                index = -2;
+            }
+        }
+
+        // BEGIN Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+        FormatSpecifier(String indexStr, String flagsStr, String widthStr,
+                        String precisionStr, String tTStr, String convStr) {
+            index(indexStr);
+            flags(flagsStr);
+            width(widthStr);
+            precision(precisionStr);
+
+            if (tTStr != null) {
+                dt = true;
+                if (tTStr.equals("T")) {
+                    f.add(Flags.UPPERCASE);
+                }
+            }
+
+            conversion(convStr.charAt(0));
+        // END Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+            if (dt)
+                checkDateTime();
+            else if (Conversion.isGeneral(c))
+                checkGeneral();
+            else if (Conversion.isCharacter(c))
+                checkCharacter();
+            else if (Conversion.isInteger(c))
+                checkInteger();
+            else if (Conversion.isFloat(c))
+                checkFloat();
+            else if (Conversion.isText(c))
+                checkText();
+            else
+                throw new UnknownFormatConversionException(String.valueOf(c));
+        }
+
+        public void print(Object arg, Locale l) throws IOException {
+            if (dt) {
+                printDateTime(arg, l);
+                return;
+            }
+            switch(c) {
+            case Conversion.DECIMAL_INTEGER:
+            case Conversion.OCTAL_INTEGER:
+            case Conversion.HEXADECIMAL_INTEGER:
+                printInteger(arg, l);
+                break;
+            case Conversion.SCIENTIFIC:
+            case Conversion.GENERAL:
+            case Conversion.DECIMAL_FLOAT:
+            case Conversion.HEXADECIMAL_FLOAT:
+                printFloat(arg, l);
+                break;
+            case Conversion.CHARACTER:
+                printCharacter(arg, l);
+                break;
+            case Conversion.BOOLEAN:
+                printBoolean(arg, l);
+                break;
+            case Conversion.STRING:
+                printString(arg, l);
+                break;
+            case Conversion.HASHCODE:
+                printHashCode(arg, l);
+                break;
+            case Conversion.LINE_SEPARATOR:
+                a.append(System.lineSeparator());
+                break;
+            case Conversion.PERCENT_SIGN:
+                print("%", l);
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void printInteger(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null", l);
+            else if (arg instanceof Byte)
+                print(((Byte)arg).byteValue(), l);
+            else if (arg instanceof Short)
+                print(((Short)arg).shortValue(), l);
+            else if (arg instanceof Integer)
+                print(((Integer)arg).intValue(), l);
+            else if (arg instanceof Long)
+                print(((Long)arg).longValue(), l);
+            else if (arg instanceof BigInteger)
+                print(((BigInteger)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printFloat(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null", l);
+            else if (arg instanceof Float)
+                print(((Float)arg).floatValue(), l);
+            else if (arg instanceof Double)
+                print(((Double)arg).doubleValue(), l);
+            else if (arg instanceof BigDecimal)
+                print(((BigDecimal)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printDateTime(Object arg, Locale l) throws IOException {
+            if (arg == null) {
+                print("null", l);
+                return;
+            }
+            Calendar cal = null;
+
+            // Instead of Calendar.setLenient(true), perhaps we should
+            // wrap the IllegalArgumentException that might be thrown?
+            if (arg instanceof Long) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTimeInMillis((Long)arg);
+            } else if (arg instanceof Date) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTime((Date)arg);
+            } else if (arg instanceof Calendar) {
+                cal = (Calendar) ((Calendar) arg).clone();
+                cal.setLenient(true);
+            } else if (arg instanceof TemporalAccessor) {
+                print((TemporalAccessor) arg, c, l);
+                return;
+            } else {
+                failConversion(c, arg);
+            }
+            // Use the provided locale so that invocations of
+            // localizedMagnitude() use optimizations for null.
+            print(cal, c, l);
+        }
+
+        private void printCharacter(Object arg, Locale l) throws IOException {
+            if (arg == null) {
+                print("null", l);
+                return;
+            }
+            String s = null;
+            if (arg instanceof Character) {
+                s = ((Character)arg).toString();
+            } else if (arg instanceof Byte) {
+                byte i = (Byte) arg;
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Short) {
+                short i = (Short) arg;
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Integer) {
+                int i = (Integer) arg;
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else {
+                failConversion(c, arg);
+            }
+            print(s, l);
+        }
+
+        private void printString(Object arg, Locale l) throws IOException {
+            if (arg instanceof Formattable) {
+                Formatter fmt = Formatter.this;
+                if (fmt.locale() != l)
+                    fmt = new Formatter(fmt.out(), l);
+                ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
+            } else {
+                if (f.contains(Flags.ALTERNATE))
+                    failMismatch(Flags.ALTERNATE, 's');
+                if (arg == null)
+                    print("null", l);
+                else
+                    print(arg.toString(), l);
+            }
+        }
+
+        private void printBoolean(Object arg, Locale l) throws IOException {
+            String s;
+            if (arg != null)
+                s = ((arg instanceof Boolean)
+                     ? ((Boolean)arg).toString()
+                     : Boolean.toString(true));
+            else
+                s = Boolean.toString(false);
+            print(s, l);
+        }
+
+        private void printHashCode(Object arg, Locale l) throws IOException {
+            String s = (arg == null
+                        ? "null"
+                        : Integer.toHexString(arg.hashCode()));
+            print(s, l);
+        }
+
+        private void print(String s, Locale l) throws IOException {
+            if (precision != -1 && precision < s.length())
+                s = s.substring(0, precision);
+            if (f.contains(Flags.UPPERCASE))
+                s = toUpperCaseWithLocale(s, l);
+            appendJustified(a, s);
+        }
+
+        private String toUpperCaseWithLocale(String s, Locale l) {
+            return s.toUpperCase(Objects.requireNonNullElse(l,
+                    Locale.getDefault(Locale.Category.FORMAT)));
+        }
+
+        private void appendJustified(Appendable a, CharSequence cs) throws IOException {
+             if (width == -1) {
+                 a.append(cs);
+                 return;
+             }
+             boolean padRight = f.contains(Flags.LEFT_JUSTIFY);
+             int sp = width - cs.length();
+             if (padRight) {
+                 a.append(cs);
+             }
+             for (int i = 0; i < sp; i++) {
+                 a.append(' ');
+             }
+             if (!padRight) {
+                 a.append(cs);
+             }
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder("%");
+            // Flags.UPPERCASE is set internally for legal conversions.
+            Flags dupf = f.dup().remove(Flags.UPPERCASE);
+            sb.append(dupf.toString());
+            if (index > 0)
+                sb.append(index).append('$');
+            if (width != -1)
+                sb.append(width);
+            if (precision != -1)
+                sb.append('.').append(precision);
+            if (dt)
+                sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't');
+            sb.append(f.contains(Flags.UPPERCASE)
+                      ? Character.toUpperCase(c) : c);
+            return sb.toString();
+        }
+
+        private void checkGeneral() {
+            if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE)
+                && f.contains(Flags.ALTERNATE))
+                failMismatch(Flags.ALTERNATE, c);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+            checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD,
+                          Flags.GROUP, Flags.PARENTHESES);
+        }
+
+        private void checkDateTime() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            if (!DateTime.isValid(c))
+                throw new UnknownFormatConversionException("t" + c);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkCharacter() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkInteger() {
+            checkNumeric();
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+
+            if (c == Conversion.DECIMAL_INTEGER)
+                checkBadFlags(Flags.ALTERNATE);
+            else if (c == Conversion.OCTAL_INTEGER)
+                checkBadFlags(Flags.GROUP);
+            else
+                checkBadFlags(Flags.GROUP);
+        }
+
+        private void checkBadFlags(Flags ... badFlags) {
+            for (Flags badFlag : badFlags)
+                if (f.contains(badFlag))
+                    failMismatch(badFlag, c);
+        }
+
+        private void checkFloat() {
+            checkNumeric();
+            if (c == Conversion.DECIMAL_FLOAT) {
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                checkBadFlags(Flags.PARENTHESES, Flags.GROUP);
+            } else if (c == Conversion.SCIENTIFIC) {
+                checkBadFlags(Flags.GROUP);
+            } else if (c == Conversion.GENERAL) {
+                checkBadFlags(Flags.ALTERNATE);
+            }
+        }
+
+        private void checkNumeric() {
+            if (width != -1 && width < 0)
+                throw new IllegalFormatWidthException(width);
+
+            if (precision != -1 && precision < 0)
+                throw new IllegalFormatPrecisionException(precision);
+
+            // '-' and '0' require a width
+            if (width == -1
+                && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD)))
+                throw new MissingFormatWidthException(toString());
+
+            // bad combination
+            if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE))
+                || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD)))
+                throw new IllegalFormatFlagsException(f.toString());
+        }
+
+        private void checkText() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            switch (c) {
+            case Conversion.PERCENT_SIGN:
+                if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf()
+                    && f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                // '-' requires a width
+                if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                    throw new MissingFormatWidthException(toString());
+                break;
+            case Conversion.LINE_SEPARATOR:
+                if (width != -1)
+                    throw new IllegalFormatWidthException(width);
+                if (f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void print(byte value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 8);
+            }
+            print(v, l);
+        }
+
+        private void print(short value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 16);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(int value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 32);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(long value, Locale l) throws IOException {
+
+            StringBuilder sb = new StringBuilder();
+
+            if (c == Conversion.DECIMAL_INTEGER) {
+                boolean neg = value < 0;
+                String valueStr = Long.toString(value, 10);
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l);
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toOctalString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 1
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append('0');
+                if (f.contains(Flags.ZERO_PAD)) {
+                    trailingZeros(sb, width - len);
+                }
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toHexString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 2
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                if (f.contains(Flags.ZERO_PAD)) {
+                    trailingZeros(sb, width - len);
+                }
+                if (f.contains(Flags.UPPERCASE))
+                    s = toUpperCaseWithLocale(s, l);
+                sb.append(s);
+            }
+
+            // justify based on width
+            appendJustified(a, sb);
+        }
+
+        // neg := val < 0
+        private StringBuilder leadingSign(StringBuilder sb, boolean neg) {
+            if (!neg) {
+                if (f.contains(Flags.PLUS)) {
+                    sb.append('+');
+                } else if (f.contains(Flags.LEADING_SPACE)) {
+                    sb.append(' ');
+                }
+            } else {
+                if (f.contains(Flags.PARENTHESES))
+                    sb.append('(');
+                else
+                    sb.append('-');
+            }
+            return sb;
+        }
+
+        // neg := val < 0
+        private StringBuilder trailingSign(StringBuilder sb, boolean neg) {
+            if (neg && f.contains(Flags.PARENTHESES))
+                sb.append(')');
+            return sb;
+        }
+
+        private void print(BigInteger value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigInteger v = value.abs();
+
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            if (c == Conversion.DECIMAL_INTEGER) {
+                localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                String s = v.toString(8);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len++;
+                    sb.append('0');
+                }
+                if (f.contains(Flags.ZERO_PAD)) {
+                    trailingZeros(sb, width - len);
+                }
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                String s = v.toString(16);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len += 2;
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                }
+                if (f.contains(Flags.ZERO_PAD)) {
+                    trailingZeros(sb, width - len);
+                }
+                if (f.contains(Flags.UPPERCASE))
+                    s = toUpperCaseWithLocale(s, l);
+                sb.append(s);
+            }
+
+            // trailing sign indicator
+            trailingSign(sb, (value.signum() == -1));
+
+            // justify based on width
+            appendJustified(a, sb);
+        }
+
+        private void print(float value, Locale l) throws IOException {
+            print((double) value, l);
+        }
+
+        private void print(double value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = Double.compare(value, 0.0) == -1;
+
+            if (!Double.isNaN(value)) {
+                double v = Math.abs(value);
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                if (!Double.isInfinite(v))
+                    print(sb, v, l, f, c, precision, neg);
+                else
+                    sb.append(f.contains(Flags.UPPERCASE)
+                              ? "INFINITY" : "Infinity");
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else {
+                sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN");
+            }
+
+            // justify based on width
+            appendJustified(a, sb);
+        }
+
+        // !Double.isInfinite(value) && !Double.isNaN(value)
+        private void print(StringBuilder sb, double value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.SCIENTIFIC);
+
+                StringBuilder mant = new StringBuilder().append(fd.getMantissa());
+                addZeros(mant, prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0)) {
+                    mant.append('.');
+                }
+
+                char[] exp = (value == 0.0)
+                    ? new char[] {'+','0','0'} : fd.getExponent();
+
+                int newW = width;
+                if (width != -1) {
+                    newW = adjustWidth(width - exp.length - 1, f, neg);
+                }
+                localizedMagnitude(sb, mant, 0, f, newW, l);
+
+                // BEGIN Android-changed: Use localized exponent separator for %e.
+                Locale separatorLocale = (l != null) ? l : Locale.getDefault();
+                DecimalFormatData formatData = DecimalFormatData.getInstance(separatorLocale);
+                sb.append(f.contains(Flags.UPPERCASE) ?
+                        formatData.getExponentSeparator().toUpperCase(separatorLocale) :
+                        formatData.getExponentSeparator().toLowerCase(separatorLocale));
+                // END Android-changed: Use localized exponent separator for %e.
+
+                char sign = exp[0];
+                assert(sign == '+' || sign == '-');
+                sb.append(sign);
+
+                localizedMagnitudeExp(sb, exp, 1, l);
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+
+                StringBuilder mant = new StringBuilder().append(fd.getMantissa());
+                addZeros(mant, prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant.append('.');
+
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width, f, neg);
+                localizedMagnitude(sb, mant, 0, f, newW, l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                char[] exp;
+                StringBuilder mant = new StringBuilder();
+                int expRounded;
+                if (value == 0.0) {
+                    exp = null;
+                    mant.append('0');
+                    expRounded = 0;
+                } else {
+                    FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.GENERAL);
+                    exp = fd.getExponent();
+                    mant.append(fd.getMantissa());
+                    expRounded = fd.getExponentRounded();
+                }
+
+                if (exp != null) {
+                    prec -= 1;
+                } else {
+                    prec -= expRounded + 1;
+                }
+
+                addZeros(mant, prec);
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0)) {
+                    mant.append('.');
+                }
+
+                int newW = width;
+                if (width != -1) {
+                    if (exp != null)
+                        newW = adjustWidth(width - exp.length - 1, f, neg);
+                    else
+                        newW = adjustWidth(width, f, neg);
+                }
+                localizedMagnitude(sb, mant, 0, f, newW, l);
+
+                if (exp != null) {
+                    sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                    char sign = exp[0];
+                    assert(sign == '+' || sign == '-');
+                    sb.append(sign);
+
+                    localizedMagnitudeExp(sb, exp, 1, l);
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                int prec = precision;
+                if (precision == -1)
+                    // assume that we want all of the digits
+                    prec = 0;
+                else if (precision == 0)
+                    prec = 1;
+
+                String s = hexDouble(value, prec);
+
+                StringBuilder va = new StringBuilder();
+                boolean upper = f.contains(Flags.UPPERCASE);
+                sb.append(upper ? "0X" : "0x");
+
+                if (f.contains(Flags.ZERO_PAD)) {
+                    int leadingCharacters = 2;
+                    if(f.contains(Flags.LEADING_SPACE) ||
+                            f.contains(Flags.PLUS) || neg) {
+                        leadingCharacters = 3;
+                    }
+                    trailingZeros(sb, width - s.length() - leadingCharacters);
+                }
+
+                int idx = s.indexOf('p');
+                if (upper) {
+                    String tmp = s.substring(0, idx);
+                    // don't localize hex
+                    tmp = tmp.toUpperCase(Locale.ROOT);
+                    va.append(tmp);
+                } else {
+                    va.append(s, 0, idx);
+                }
+                if (prec != 0) {
+                    addZeros(va, prec);
+                }
+                sb.append(va);
+                sb.append(upper ? 'P' : 'p');
+                sb.append(s, idx+1, s.length());
+            }
+        }
+
+        // Add zeros to the requested precision.
+        private void addZeros(StringBuilder sb, int prec) {
+            // Look for the dot.  If we don't find one, the we'll need to add
+            // it before we add the zeros.
+            int len = sb.length();
+            int i;
+            for (i = 0; i < len; i++) {
+                if (sb.charAt(i) == '.') {
+                    break;
+                }
+            }
+            boolean needDot = false;
+            if (i == len) {
+                needDot = true;
+            }
+
+            // Determine existing precision.
+            int outPrec = len - i - (needDot ? 0 : 1);
+            assert (outPrec <= prec);
+            if (outPrec == prec) {
+                return;
+            }
+
+            // Add dot if previously determined to be necessary.
+            if (needDot) {
+                sb.append('.');
+            }
+
+            // Add zeros.
+            trailingZeros(sb, prec - outPrec);
+        }
+
+        // Method assumes that d > 0.
+        private String hexDouble(double d, int prec) {
+            // Let Double.toHexString handle simple cases
+            if (!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) {
+                // remove "0x"
+                return Double.toHexString(d).substring(2);
+            } else {
+                assert(prec >= 1 && prec <= 12);
+
+                int exponent  = Math.getExponent(d);
+                boolean subnormal
+                    = (exponent == Double.MIN_EXPONENT - 1);
+
+                // If this is subnormal input so normalize (could be faster to
+                // do as integer operation).
+                if (subnormal) {
+                    double scaleUp = Math.scalb(1.0, 54);
+                    d *= scaleUp;
+                    // Calculate the exponent.  This is not just exponent + 54
+                    // since the former is not the normalized exponent.
+                    exponent = Math.getExponent(d);
+                    assert exponent >= Double.MIN_EXPONENT &&
+                        exponent <= Double.MAX_EXPONENT: exponent;
+                }
+
+                int precision = 1 + prec*4;
+                int shiftDistance
+                    =  DoubleConsts.SIGNIFICAND_WIDTH - precision;
+                assert(shiftDistance >= 1 && shiftDistance < DoubleConsts.SIGNIFICAND_WIDTH);
+
+                long doppel = Double.doubleToLongBits(d);
+                // Deterime the number of bits to keep.
+                long newSignif
+                    = (doppel & (DoubleConsts.EXP_BIT_MASK
+                                 | DoubleConsts.SIGNIF_BIT_MASK))
+                                     >> shiftDistance;
+                // Bits to round away.
+                long roundingBits = doppel & ~(~0L << shiftDistance);
+
+                // To decide how to round, look at the low-order bit of the
+                // working significand, the highest order discarded bit (the
+                // round bit) and whether any of the lower order discarded bits
+                // are nonzero (the sticky bit).
+
+                boolean leastZero = (newSignif & 0x1L) == 0L;
+                boolean round
+                    = ((1L << (shiftDistance - 1) ) & roundingBits) != 0L;
+                boolean sticky  = shiftDistance > 1 &&
+                    (~(1L<< (shiftDistance - 1)) & roundingBits) != 0;
+                if((leastZero && round && sticky) || (!leastZero && round)) {
+                    newSignif++;
+                }
+
+                long signBit = doppel & DoubleConsts.SIGN_BIT_MASK;
+                newSignif = signBit | (newSignif << shiftDistance);
+                double result = Double.longBitsToDouble(newSignif);
+
+                if (Double.isInfinite(result) ) {
+                    // Infinite result generated by rounding
+                    return "1.0p1024";
+                } else {
+                    String res = Double.toHexString(result).substring(2);
+                    if (!subnormal)
+                        return res;
+                    else {
+                        // Create a normalized subnormal string.
+                        int idx = res.indexOf('p');
+                        if (idx == -1) {
+                            // No 'p' character in hex string.
+                            assert false;
+                            return null;
+                        } else {
+                            // Get exponent and append at the end.
+                            String exp = res.substring(idx + 1);
+                            int iexp = Integer.parseInt(exp) -54;
+                            return res.substring(0, idx) + "p"
+                                + Integer.toString(iexp);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void print(BigDecimal value, Locale l) throws IOException {
+            if (c == Conversion.HEXADECIMAL_FLOAT)
+                failConversion(c, value);
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigDecimal v = value.abs();
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            print(sb, v, l, f, c, precision, neg);
+
+            // trailing sign indicator
+            trailingSign(sb, neg);
+
+            // justify based on width
+            appendJustified(a, sb);
+        }
+
+        // value > 0
+        private void print(StringBuilder sb, BigDecimal value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+                int origPrec = value.precision();
+                int nzeros = 0;
+                int compPrec;
+
+                if (prec > origPrec - 1) {
+                    compPrec = origPrec;
+                    nzeros = prec - (origPrec - 1);
+                } else {
+                    compPrec = prec + 1;
+                }
+
+                MathContext mc = new MathContext(compPrec);
+                BigDecimal v
+                    = new BigDecimal(value.unscaledValue(), scale, mc);
+
+                BigDecimalLayout bdl
+                    = new BigDecimalLayout(v.unscaledValue(), v.scale(),
+                                           BigDecimalLayoutForm.SCIENTIFIC);
+
+                StringBuilder mant = bdl.mantissa();
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part) or the original
+                // precision is one. Append a decimal point if '#' is set or if
+                // we require zero padding to get to the requested precision.
+                if ((origPrec == 1 || !bdl.hasDot())
+                        && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) {
+                    mant.append('.');
+                }
+
+                // Add trailing zeros in the case precision is greater than
+                // the number of available digits after the decimal separator.
+                trailingZeros(mant, nzeros);
+
+                StringBuilder exp = bdl.exponent();
+                int newW = width;
+                if (width != -1) {
+                    newW = adjustWidth(width - exp.length() - 1, f, neg);
+                }
+                localizedMagnitude(sb, mant, 0, f, newW, l);
+
+                sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                Flags flags = f.dup().remove(Flags.GROUP);
+                char sign = exp.charAt(0);
+                assert(sign == '+' || sign == '-');
+                sb.append(sign);
+
+                sb.append(localizedMagnitude(null, exp, 1, flags, -1, l));
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+
+                if (scale > prec) {
+                    // more "scale" digits than the requested "precision"
+                    int compPrec = value.precision();
+                    if (compPrec <= scale) {
+                        // case of 0.xxxxxx
+                        value = value.setScale(prec, RoundingMode.HALF_UP);
+                    } else {
+                        compPrec -= (scale - prec);
+                        value = new BigDecimal(value.unscaledValue(),
+                                               scale,
+                                               new MathContext(compPrec));
+                    }
+                }
+                BigDecimalLayout bdl = new BigDecimalLayout(
+                                           value.unscaledValue(),
+                                           value.scale(),
+                                           BigDecimalLayoutForm.DECIMAL_FLOAT);
+
+                StringBuilder mant = bdl.mantissa();
+                int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0);
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part).  Append a decimal
+                // point if '#' is set or we require zero padding to get to the
+                // requested precision.
+                if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE)
+                        || nzeros > 0)) {
+                    mant.append('.');
+                }
+
+                // Add trailing zeros if the precision is greater than the
+                // number of available digits after the decimal separator.
+                trailingZeros(mant, nzeros);
+
+                localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                value = value.round(new MathContext(prec));
+                if ((value.equals(BigDecimal.ZERO))
+                    || ((value.compareTo(BigDecimal.valueOf(1, 4)) != -1)
+                        && (value.compareTo(BigDecimal.valueOf(1, -prec)) == -1))) {
+
+                    int e = - value.scale()
+                        + (value.unscaledValue().toString().length() - 1);
+
+                    // xxx.yyy
+                    //   g precision (# sig digits) = #x + #y
+                    //   f precision = #y
+                    //   exponent = #x - 1
+                    // => f precision = g precision - exponent - 1
+                    // 0.000zzz
+                    //   g precision (# sig digits) = #z
+                    //   f precision = #0 (after '.') + #z
+                    //   exponent = - #0 (after '.') - 1
+                    // => f precision = g precision - exponent - 1
+                    prec = prec - e - 1;
+
+                    print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec,
+                          neg);
+                } else {
+                    print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                // This conversion isn't supported.  The error should be
+                // reported earlier.
+                assert false;
+            }
+        }
+
+        private class BigDecimalLayout {
+            private StringBuilder mant;
+            private StringBuilder exp;
+            private boolean dot = false;
+            private int scale;
+
+            public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                layout(intVal, scale, form);
+            }
+
+            public boolean hasDot() {
+                return dot;
+            }
+
+            public int scale() {
+                return scale;
+            }
+
+            public StringBuilder mantissa() {
+                return mant;
+            }
+
+            // The exponent will be formatted as a sign ('+' or '-') followed
+            // by the exponent zero-padded to include at least two digits.
+            public StringBuilder exponent() {
+                return exp;
+            }
+
+            private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                String coeff = intVal.toString();
+                this.scale = scale;
+
+                // Construct a buffer, with sufficient capacity for all cases.
+                // If E-notation is needed, length will be: +1 if negative, +1
+                // if '.' needed, +2 for "E+", + up to 10 for adjusted
+                // exponent.  Otherwise it could have +1 if negative, plus
+                // leading "0.00000"
+                int len = coeff.length();
+                mant = new StringBuilder(len + 14);
+
+                if (scale == 0) {
+                    if (len > 1) {
+                        mant.append(coeff.charAt(0));
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC) {
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, 1, len);
+                            exp = new StringBuilder("+");
+                            if (len < 10) {
+                                exp.append('0').append(len - 1);
+                            } else {
+                                exp.append(len - 1);
+                            }
+                        } else {
+                            mant.append(coeff, 1, len);
+                        }
+                    } else {
+                        mant.append(coeff);
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC) {
+                            exp = new StringBuilder("+00");
+                        }
+                    }
+                } else if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) {
+                    // count of padding zeros
+
+                    if (scale >= len) {
+                        // 0.xxx form
+                        mant.append("0.");
+                        dot = true;
+                        trailingZeros(mant, scale - len);
+                        mant.append(coeff);
+                    } else {
+                        if (scale > 0) {
+                            // xx.xx form
+                            int pad = len - scale;
+                            mant.append(coeff, 0, pad);
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, pad, len);
+                        } else { // scale < 0
+                            // xx form
+                            mant.append(coeff, 0, len);
+                            if (intVal.signum() != 0) {
+                                trailingZeros(mant, -scale);
+                            }
+                            this.scale = 0;
+                        }
+                    }
+                } else {
+                    // x.xxx form
+                    mant.append(coeff.charAt(0));
+                    if (len > 1) {
+                        mant.append('.');
+                        dot = true;
+                        mant.append(coeff, 1, len);
+                    }
+                    exp = new StringBuilder();
+                    long adjusted = -(long) scale + (len - 1);
+                    if (adjusted != 0) {
+                        long abs = Math.abs(adjusted);
+                        // require sign
+                        exp.append(adjusted < 0 ? '-' : '+');
+                        if (abs < 10) {
+                            exp.append('0');
+                        }
+                        exp.append(abs);
+                    } else {
+                        exp.append("+00");
+                    }
+                }
+            }
+        }
+
+        private int adjustWidth(int width, Flags f, boolean neg) {
+            int newW = width;
+            if (newW != -1 && neg && f.contains(Flags.PARENTHESES))
+                newW--;
+            return newW;
+        }
+
+        // Add trailing zeros
+        private void trailingZeros(StringBuilder sb, int nzeros) {
+            for (int i = 0; i < nzeros; i++) {
+                sb.append('0');
+            }
+        }
+
+        private void print(Calendar t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+
+            // justify based on width
+            if (f.contains(Flags.UPPERCASE)) {
+                appendJustified(a, toUpperCaseWithLocale(sb.toString(), l));
+            } else {
+                appendJustified(a, sb);
+            }
+        }
+
+        private Appendable print(StringBuilder sb, Calendar t, char c, Locale l)
+                throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            switch (c) {
+            case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23)
+            case DateTime.HOUR_0:        // 'I' (01 - 12)
+            case DateTime.HOUR_OF_DAY:   // 'k' (0 - 23) -- like H
+            case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                int i = t.get(Calendar.HOUR_OF_DAY);
+                if (c == DateTime.HOUR_0 || c == DateTime.HOUR)
+                    i = (i == 0 || i == 12 ? 12 : i % 12);
+                Flags flags = (c == DateTime.HOUR_OF_DAY_0
+                               || c == DateTime.HOUR_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.MINUTE:      { // 'M' (00 - 59)
+                int i = t.get(Calendar.MINUTE);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                int i = t.get(Calendar.MILLISECOND) * 1000000;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 9, l));
+                break;
+            }
+            case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                int i = t.get(Calendar.MILLISECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                long i = t.getTimeInMillis();
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.AM_PM:       { // 'p' (am or pm)
+                // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                String[] ampm = { "AM", "PM" };
+                if (l != null && l != Locale.US) {
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                    ampm = dfs.getAmPmStrings();
+                }
+                String s = ampm[t.get(Calendar.AM_PM)];
+                sb.append(s.toLowerCase(Objects.requireNonNullElse(l,
+                            Locale.getDefault(Locale.Category.FORMAT))));
+                break;
+            }
+            case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                long i = t.getTimeInMillis() / 1000;
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                int i = t.get(Calendar.SECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                int i = t.get(Calendar.ZONE_OFFSET) + t.get(Calendar.DST_OFFSET);
+                boolean neg = i < 0;
+                sb.append(neg ? '-' : '+');
+                if (neg)
+                    i = -i;
+                int min = i / 60000;
+                // combine minute and hour into a single integer
+                int offset = (min / 60) * 100 + (min % 60);
+                Flags flags = Flags.ZERO_PAD;
+
+                sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                break;
+            }
+            case DateTime.ZONE:        { // 'Z' (symbol)
+                TimeZone tz = t.getTimeZone();
+                sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
+                                           TimeZone.SHORT,
+                                           Objects.requireNonNullElse(l, Locale.US)));
+                break;
+            }
+
+            // Date
+            case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+            case DateTime.NAME_OF_DAY:          { // 'A'
+                int i = t.get(Calendar.DAY_OF_WEEK);
+                Locale lt = Objects.requireNonNullElse(l, Locale.US);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_DAY)
+                    sb.append(dfs.getWeekdays()[i]);
+                else
+                    sb.append(dfs.getShortWeekdays()[i]);
+                break;
+            }
+            case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+            case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+            case DateTime.NAME_OF_MONTH:        { // 'B'
+                int i = t.get(Calendar.MONTH);
+                Locale lt = Objects.requireNonNullElse(l, Locale.US);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_MONTH)
+                    sb.append(dfs.getMonths()[i]);
+                else
+                    sb.append(dfs.getShortMonths()[i]);
+                break;
+            }
+            case DateTime.CENTURY:                // 'C' (00 - 99)
+            case DateTime.YEAR_2:                 // 'y' (00 - 99)
+            case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                int i = t.get(Calendar.YEAR);
+                int size = 2;
+                switch (c) {
+                    case DateTime.CENTURY -> i /= 100;
+                    case DateTime.YEAR_2  -> i %= 100;
+                    case DateTime.YEAR_4  -> size = 4;
+                }
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, size, l));
+                break;
+            }
+            case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+            case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                int i = t.get(Calendar.DATE);
+                Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                int i = t.get(Calendar.DAY_OF_YEAR);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MONTH:                { // 'm' (01 - 12)
+                int i = t.get(Calendar.MONTH) + 1;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+
+            // Composites
+            case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+            case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l);
+                if (c == DateTime.TIME) {
+                    sb.append(sep);
+                    print(sb, t, DateTime.SECOND, l);
+                }
+                break;
+            }
+            case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l).append(sep);
+                print(sb, t, DateTime.SECOND, l).append(' ');
+                // this may be in wrong place for some locales
+                StringBuilder tsb = new StringBuilder();
+                print(tsb, t, DateTime.AM_PM, l);
+
+                sb.append(toUpperCaseWithLocale(tsb.toString(), l));
+                break;
+            }
+            case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                char sep = ' ';
+                print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.TIME, l).append(sep);
+                print(sb, t, DateTime.ZONE, l).append(sep);
+                print(sb, t, DateTime.YEAR_4, l);
+                break;
+            }
+            case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                char sep = '/';
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.YEAR_2, l);
+                break;
+            }
+            case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                char sep = '-';
+                print(sb, t, DateTime.YEAR_4, l).append(sep);
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                break;
+            }
+            default:
+                assert false;
+            }
+            return sb;
+        }
+
+        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+            // justify based on width
+            if (f.contains(Flags.UPPERCASE)) {
+                appendJustified(a, toUpperCaseWithLocale(sb.toString(), l));
+            } else {
+                appendJustified(a, sb);
+            }
+        }
+
+        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+                                 Locale l) throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            try {
+                switch (c) {
+                case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_0:      {  // 'I' (01 - 12)
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.MINUTE:      { // 'M' (00 - 59)
+                    int i = t.get(ChronoField.MINUTE_OF_HOUR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                    int i;
+                    try {
+                        i = t.get(ChronoField.NANO_OF_SECOND);
+                    } catch (UnsupportedTemporalTypeException u) {
+                        i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    break;
+                }
+                case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
+                             t.getLong(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.AM_PM:       { // 'p' (am or pm)
+                    // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                    String[] ampm = { "AM", "PM" };
+                    if (l != null && l != Locale.US) {
+                        DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                        ampm = dfs.getAmPmStrings();
+                    }
+                    String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
+                    sb.append(s.toLowerCase(Objects.requireNonNullElse(l,
+                            Locale.getDefault(Locale.Category.FORMAT))));
+                    break;
+                }
+                case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                    int i = t.get(ChronoField.SECOND_OF_MINUTE);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                    int i = t.get(ChronoField.OFFSET_SECONDS);
+                    boolean neg = i < 0;
+                    sb.append(neg ? '-' : '+');
+                    if (neg)
+                        i = -i;
+                    int min = i / 60;
+                    // combine minute and hour into a single integer
+                    int offset = (min / 60) * 100 + (min % 60);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    break;
+                }
+                case DateTime.ZONE:        { // 'Z' (symbol)
+                    ZoneId zid = t.query(TemporalQueries.zone());
+                    if (zid == null) {
+                        throw new IllegalFormatConversionException(c, t.getClass());
+                    }
+                    if (!(zid instanceof ZoneOffset) &&
+                        t.isSupported(ChronoField.INSTANT_SECONDS)) {
+                        Instant instant = Instant.from(t);
+                        sb.append(TimeZone.getTimeZone(zid.getId())
+                                          .getDisplayName(zid.getRules().isDaylightSavings(instant),
+                                                          TimeZone.SHORT,
+                                                          Objects.requireNonNullElse(l, Locale.US)));
+                        break;
+                    }
+                    sb.append(zid.getId());
+                    break;
+                }
+                // Date
+                case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+                case DateTime.NAME_OF_DAY:          { // 'A'
+                    int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
+                    Locale lt = Objects.requireNonNullElse(l, Locale.US);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_DAY)
+                        sb.append(dfs.getWeekdays()[i]);
+                    else
+                        sb.append(dfs.getShortWeekdays()[i]);
+                    break;
+                }
+                case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+                case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+                case DateTime.NAME_OF_MONTH:        { // 'B'
+                    int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
+                    Locale lt = Objects.requireNonNullElse(l, Locale.US);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_MONTH)
+                        sb.append(dfs.getMonths()[i]);
+                    else
+                        sb.append(dfs.getShortMonths()[i]);
+                    break;
+                }
+                case DateTime.CENTURY:                // 'C' (00 - 99)
+                case DateTime.YEAR_2:                 // 'y' (00 - 99)
+                case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                    int i = t.get(ChronoField.YEAR_OF_ERA);
+                    int size = 2;
+                    switch (c) {
+                        case DateTime.CENTURY -> i /= 100;
+                        case DateTime.YEAR_2  -> i %= 100;
+                        case DateTime.YEAR_4  -> size = 4;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    break;
+                }
+                case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+                case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                    int i = t.get(ChronoField.DAY_OF_MONTH);
+                    Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                                   ? Flags.ZERO_PAD
+                                   : Flags.NONE);
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                    int i = t.get(ChronoField.DAY_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MONTH:                { // 'm' (01 - 12)
+                    int i = t.get(ChronoField.MONTH_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+
+                // Composites
+                case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+                case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l);
+                    if (c == DateTime.TIME) {
+                        sb.append(sep);
+                        print(sb, t, DateTime.SECOND, l);
+                    }
+                    break;
+                }
+                case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l).append(sep);
+                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    // this may be in wrong place for some locales
+                    StringBuilder tsb = new StringBuilder();
+                    print(tsb, t, DateTime.AM_PM, l);
+                    sb.append(toUpperCaseWithLocale(tsb.toString(), l));
+                    break;
+                }
+                case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                    char sep = ' ';
+                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.TIME, l).append(sep);
+                    print(sb, t, DateTime.ZONE, l).append(sep);
+                    print(sb, t, DateTime.YEAR_4, l);
+                    break;
+                }
+                case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                    char sep = '/';
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.YEAR_2, l);
+                    break;
+                }
+                case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                    char sep = '-';
+                    print(sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    break;
+                }
+                default:
+                    assert false;
+                }
+            } catch (DateTimeException x) {
+                throw new IllegalFormatConversionException(c, t.getClass());
+            }
+            return sb;
+        }
+
+        // -- Methods to support throwing exceptions --
+
+        private void failMismatch(Flags f, char c) {
+            String fs = f.toString();
+            throw new FormatFlagsConversionMismatchException(fs, c);
+        }
+
+        private void failConversion(char c, Object arg) {
+            throw new IllegalFormatConversionException(c, arg.getClass());
+        }
+
+        private char getZero(Locale l) {
+            if ((l != null) &&  !l.equals(locale())) {
+                // Android-changed: Improve the performance by 10x http://b/197788756
+                // Unclear if this mapping is needed but inherited from DecimalFormatSymbols
+                l = LocaleData.mapInvalidAndNullLocales(l);
+                DecimalFormatData decimalFormatData = DecimalFormatData.getInstance(l);
+                return decimalFormatData.getZeroDigit();
+                //  DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                //  return dfs.getZeroDigit();
+            }
+            return zero();
+        }
+
+        private StringBuilder localizedMagnitude(StringBuilder sb,
+                long value, Flags f, int width, Locale l) {
+            return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l);
+        }
+
+        private StringBuilder localizedMagnitude(StringBuilder sb,
+                CharSequence value, final int offset, Flags f, int width,
+                Locale l) {
+            if (sb == null) {
+                sb = new StringBuilder();
+            }
+            int begin = sb.length();
+
+            char zero = getZero(l);
+
+            // determine localized grouping separator and size
+            char grpSep = '\0';
+            int  grpSize = -1;
+            char decSep = '\0';
+
+            int len = value.length();
+            int dot = len;
+            for (int j = offset; j < len; j++) {
+                if (value.charAt(j) == '.') {
+                    dot = j;
+                    break;
+                }
+            }
+
+            if (dot < len) {
+                if (l == null || l.equals(Locale.US)) {
+                    decSep  = '.';
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    decSep  = dfs.getDecimalSeparator();
+                }
+            }
+
+            if (f.contains(Flags.GROUP)) {
+                if (l == null || l.equals(Locale.US)) {
+                    grpSep = ',';
+                    grpSize = 3;
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    grpSep = dfs.getGroupingSeparator();
+                    // Android-removed: DecimalFormat is always returned.
+                    /*
+                    DecimalFormat df = null;
+                    NumberFormat nf = NumberFormat.getNumberInstance(l);
+                    if (nf instanceof DecimalFormat) {
+                        df = (DecimalFormat) nf;
+                    } else {
+
+                        // Use DecimalFormat constructor to obtain the instance,
+                        // in case NumberFormat.getNumberInstance(l)
+                        // returns instance other than DecimalFormat
+                        LocaleProviderAdapter adapter = LocaleProviderAdapter
+                                .getAdapter(NumberFormatProvider.class, l);
+                        if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+                            adapter = LocaleProviderAdapter.getResourceBundleBased();
+                        }
+                        String[] all = adapter.getLocaleResources(l)
+                                .getNumberPatterns();
+                        df = new DecimalFormat(all[0], dfs);
+                    }
+                    */
+                    DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
+                    grpSize = df.getGroupingSize();
+
+                    if (!df.isGroupingUsed() || grpSize == 0) {
+                        grpSep = '\0';
+                    }
+                }
+            }
+
+            // localize the digits inserting group separators as necessary
+            for (int j = offset; j < len; j++) {
+                if (j == dot) {
+                    sb.append(decSep);
+                    // no more group separators after the decimal separator
+                    grpSep = '\0';
+                    continue;
+                }
+
+                char c = value.charAt(j);
+                sb.append((char) ((c - '0') + zero));
+                if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) {
+                    sb.append(grpSep);
+                }
+            }
+
+            // apply zero padding
+            if (width != -1 && f.contains(Flags.ZERO_PAD)) {
+                for (int k = sb.length(); k < width; k++) {
+                    sb.insert(begin, zero);
+                }
+            }
+
+            return sb;
+        }
+
+        // Specialized localization of exponents, where the source value can only
+        // contain characters '0' through '9', starting at index offset, and no
+        // group separators is added for any locale.
+        private void localizedMagnitudeExp(StringBuilder sb, char[] value,
+                final int offset, Locale l) {
+            char zero = getZero(l);
+
+            int len = value.length;
+            for (int j = offset; j < len; j++) {
+                char c = value[j];
+                sb.append((char) ((c - '0') + zero));
+            }
+        }
+    }
+
+    private static class Flags {
+        private int flags;
+
+        static final Flags NONE          = new Flags(0);      // ''
+
+        // duplicate declarations from Formattable.java
+        static final Flags LEFT_JUSTIFY  = new Flags(1<<0);   // '-'
+        static final Flags UPPERCASE     = new Flags(1<<1);   // '^'
+        static final Flags ALTERNATE     = new Flags(1<<2);   // '#'
+
+        // numerics
+        static final Flags PLUS          = new Flags(1<<3);   // '+'
+        static final Flags LEADING_SPACE = new Flags(1<<4);   // ' '
+        static final Flags ZERO_PAD      = new Flags(1<<5);   // '0'
+        static final Flags GROUP         = new Flags(1<<6);   // ','
+        static final Flags PARENTHESES   = new Flags(1<<7);   // '('
+
+        // indexing
+        static final Flags PREVIOUS      = new Flags(1<<8);   // '<'
+
+        private Flags(int f) {
+            flags = f;
+        }
+
+        public int valueOf() {
+            return flags;
+        }
+
+        public boolean contains(Flags f) {
+            return (flags & f.valueOf()) == f.valueOf();
+        }
+
+        public Flags dup() {
+            return new Flags(flags);
+        }
+
+        private Flags add(Flags f) {
+            flags |= f.valueOf();
+            return this;
+        }
+
+        public Flags remove(Flags f) {
+            flags &= ~f.valueOf();
+            return this;
+        }
+
+        public static Flags parse(String s, int start, int end) {
+            Flags f = new Flags(0);
+            for (int i = start; i < end; i++) {
+                char c = s.charAt(i);
+                Flags v = parse(c);
+                if (f.contains(v))
+                    throw new DuplicateFormatFlagsException(v.toString());
+                f.add(v);
+            }
+            return f;
+        }
+
+        // parse those flags which may be provided by users
+        private static Flags parse(char c) {
+            return switch (c) {
+                case '-' -> LEFT_JUSTIFY;
+                case '#' -> ALTERNATE;
+                case '+' -> PLUS;
+                case ' ' -> LEADING_SPACE;
+                case '0' -> ZERO_PAD;
+                case ',' -> GROUP;
+                case '(' -> PARENTHESES;
+                case '<' -> PREVIOUS;
+                default -> throw new UnknownFormatFlagsException(String.valueOf(c));
+            };
+        }
+
+        // Returns a string representation of the current {@code Flags}.
+        public static String toString(Flags f) {
+            return f.toString();
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (contains(LEFT_JUSTIFY))  sb.append('-');
+            if (contains(UPPERCASE))     sb.append('^');
+            if (contains(ALTERNATE))     sb.append('#');
+            if (contains(PLUS))          sb.append('+');
+            if (contains(LEADING_SPACE)) sb.append(' ');
+            if (contains(ZERO_PAD))      sb.append('0');
+            if (contains(GROUP))         sb.append(',');
+            if (contains(PARENTHESES))   sb.append('(');
+            if (contains(PREVIOUS))      sb.append('<');
+            return sb.toString();
+        }
+    }
+
+    private static class Conversion {
+        // Byte, Short, Integer, Long, BigInteger
+        // (and associated primitives due to autoboxing)
+        static final char DECIMAL_INTEGER     = 'd';
+        static final char OCTAL_INTEGER       = 'o';
+        static final char HEXADECIMAL_INTEGER = 'x';
+        static final char HEXADECIMAL_INTEGER_UPPER = 'X';
+
+        // Float, Double, BigDecimal
+        // (and associated primitives due to autoboxing)
+        static final char SCIENTIFIC          = 'e';
+        static final char SCIENTIFIC_UPPER    = 'E';
+        static final char GENERAL             = 'g';
+        static final char GENERAL_UPPER       = 'G';
+        static final char DECIMAL_FLOAT       = 'f';
+        static final char HEXADECIMAL_FLOAT   = 'a';
+        static final char HEXADECIMAL_FLOAT_UPPER = 'A';
+
+        // Character, Byte, Short, Integer
+        // (and associated primitives due to autoboxing)
+        static final char CHARACTER           = 'c';
+        static final char CHARACTER_UPPER     = 'C';
+
+        // java.util.Date, java.util.Calendar, long
+        static final char DATE_TIME           = 't';
+        static final char DATE_TIME_UPPER     = 'T';
+
+        // if (arg.TYPE != boolean) return boolean
+        // if (arg != null) return true; else return false;
+        static final char BOOLEAN             = 'b';
+        static final char BOOLEAN_UPPER       = 'B';
+        // if (arg instanceof Formattable) arg.formatTo()
+        // else arg.toString();
+        static final char STRING              = 's';
+        static final char STRING_UPPER        = 'S';
+        // arg.hashCode()
+        static final char HASHCODE            = 'h';
+        static final char HASHCODE_UPPER      = 'H';
+
+        static final char LINE_SEPARATOR      = 'n';
+        static final char PERCENT_SIGN        = '%';
+
+        static boolean isValid(char c) {
+            return switch (c) {
+                case BOOLEAN,
+                     BOOLEAN_UPPER,
+                     STRING,
+                     STRING_UPPER,
+                     HASHCODE,
+                     HASHCODE_UPPER,
+                     CHARACTER,
+                     CHARACTER_UPPER,
+                     DECIMAL_INTEGER,
+                     OCTAL_INTEGER,
+                     HEXADECIMAL_INTEGER,
+                     HEXADECIMAL_INTEGER_UPPER,
+                     SCIENTIFIC,
+                     SCIENTIFIC_UPPER,
+                     GENERAL,
+                     GENERAL_UPPER,
+                     DECIMAL_FLOAT,
+                     HEXADECIMAL_FLOAT,
+                     HEXADECIMAL_FLOAT_UPPER,
+                     LINE_SEPARATOR,
+                     PERCENT_SIGN -> true;
+                default -> false;
+            };
+        }
+
+        // Returns true iff the Conversion is applicable to all objects.
+        static boolean isGeneral(char c) {
+            return switch (c) {
+                case BOOLEAN,
+                     BOOLEAN_UPPER,
+                     STRING,
+                     STRING_UPPER,
+                     HASHCODE,
+                     HASHCODE_UPPER -> true;
+                default -> false;
+            };
+        }
+
+        // Returns true iff the Conversion is applicable to character.
+        static boolean isCharacter(char c) {
+            return switch (c) {
+                case CHARACTER,
+                     CHARACTER_UPPER -> true;
+                default -> false;
+            };
+        }
+
+        // Returns true iff the Conversion is an integer type.
+        static boolean isInteger(char c) {
+            return switch (c) {
+                case DECIMAL_INTEGER,
+                     OCTAL_INTEGER,
+                     HEXADECIMAL_INTEGER,
+                     HEXADECIMAL_INTEGER_UPPER -> true;
+                default -> false;
+            };
+        }
+
+        // Returns true iff the Conversion is a floating-point type.
+        static boolean isFloat(char c) {
+            return switch (c) {
+                case SCIENTIFIC,
+                     SCIENTIFIC_UPPER,
+                     GENERAL,
+                     GENERAL_UPPER,
+                     DECIMAL_FLOAT,
+                     HEXADECIMAL_FLOAT,
+                     HEXADECIMAL_FLOAT_UPPER -> true;
+                default -> false;
+            };
+        }
+
+        // Returns true iff the Conversion does not require an argument
+        static boolean isText(char c) {
+            return switch (c) {
+                case LINE_SEPARATOR, PERCENT_SIGN -> true;
+                default -> false;
+            };
+        }
+    }
+
+    private static class DateTime {
+        static final char HOUR_OF_DAY_0 = 'H'; // (00 - 23)
+        static final char HOUR_0        = 'I'; // (01 - 12)
+        static final char HOUR_OF_DAY   = 'k'; // (0 - 23) -- like H
+        static final char HOUR          = 'l'; // (1 - 12) -- like I
+        static final char MINUTE        = 'M'; // (00 - 59)
+        static final char NANOSECOND    = 'N'; // (000000000 - 999999999)
+        static final char MILLISECOND   = 'L'; // jdk, not in gnu (000 - 999)
+        static final char MILLISECOND_SINCE_EPOCH = 'Q'; // (0 - 99...?)
+        static final char AM_PM         = 'p'; // (am or pm)
+        static final char SECONDS_SINCE_EPOCH = 's'; // (0 - 99...?)
+        static final char SECOND        = 'S'; // (00 - 60 - leap second)
+        static final char TIME          = 'T'; // (24 hour hh:mm:ss)
+        static final char ZONE_NUMERIC  = 'z'; // (-1200 - +1200) - ls minus?
+        static final char ZONE          = 'Z'; // (symbol)
+
+        // Date
+        static final char NAME_OF_DAY_ABBREV    = 'a'; // 'a'
+        static final char NAME_OF_DAY           = 'A'; // 'A'
+        static final char NAME_OF_MONTH_ABBREV  = 'b'; // 'b'
+        static final char NAME_OF_MONTH         = 'B'; // 'B'
+        static final char CENTURY               = 'C'; // (00 - 99)
+        static final char DAY_OF_MONTH_0        = 'd'; // (01 - 31)
+        static final char DAY_OF_MONTH          = 'e'; // (1 - 31) -- like d
+        static final char NAME_OF_MONTH_ABBREV_X  = 'h'; // -- same b
+        static final char DAY_OF_YEAR           = 'j'; // (001 - 366)
+        static final char MONTH                 = 'm'; // (01 - 12)
+        static final char YEAR_2                = 'y'; // (00 - 99)
+        static final char YEAR_4                = 'Y'; // (0000 - 9999)
+
+        // Composites
+        static final char TIME_12_HOUR  = 'r'; // (hh:mm:ss [AP]M)
+        static final char TIME_24_HOUR  = 'R'; // (hh:mm same as %H:%M)
+        static final char DATE_TIME             = 'c';
+                                            // (Sat Nov 04 12:02:33 EST 1999)
+        static final char DATE                  = 'D'; // (mm/dd/yy)
+        static final char ISO_STANDARD_DATE     = 'F'; // (%Y-%m-%d)
+
+        static boolean isValid(char c) {
+            return switch (c) {
+                case HOUR_OF_DAY_0, HOUR_0, HOUR_OF_DAY, HOUR, MINUTE, NANOSECOND, MILLISECOND, MILLISECOND_SINCE_EPOCH,
+                     AM_PM, SECONDS_SINCE_EPOCH, SECOND, TIME, ZONE_NUMERIC, ZONE -> true;
+                // Date
+                case NAME_OF_DAY_ABBREV, NAME_OF_DAY, NAME_OF_MONTH_ABBREV, NAME_OF_MONTH, CENTURY, DAY_OF_MONTH_0,
+                     DAY_OF_MONTH, NAME_OF_MONTH_ABBREV_X, DAY_OF_YEAR, MONTH, YEAR_2, YEAR_4 -> true;
+                // Composites
+                case TIME_12_HOUR, TIME_24_HOUR, DATE_TIME, DATE, ISO_STANDARD_DATE -> true;
+                default -> false;
+            };
+        }
+    }
+}
diff --git a/android-35/java/util/FormatterClosedException.java b/android-35/java/util/FormatterClosedException.java
new file mode 100644
index 0000000..c75f3ff
--- /dev/null
+++ b/android-35/java/util/FormatterClosedException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the formatter has been closed.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatterClosedException extends IllegalStateException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 18111216L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FormatterClosedException() { }
+}
diff --git a/android-35/java/util/GregorianCalendar.java b/android-35/java/util/GregorianCalendar.java
new file mode 100644
index 0000000..20c1278
--- /dev/null
+++ b/android-35/java/util/GregorianCalendar.java
@@ -0,0 +1,3430 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoField;
+import libcore.util.ZoneInfo;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.JulianCalendar;
+
+/**
+ * {@code GregorianCalendar} is a concrete subclass of
+ * {@code Calendar} and provides the standard calendar system
+ * used by most of the world.
+ *
+ * <p> {@code GregorianCalendar} is a hybrid calendar that
+ * supports both the Julian and Gregorian calendar systems with the
+ * support of a single discontinuity, which corresponds by default to
+ * the Gregorian date when the Gregorian calendar was instituted
+ * (October 15, 1582 in some countries, later in others).  The cutover
+ * date may be changed by the caller by calling {@link
+ * #setGregorianChange(Date) setGregorianChange()}.
+ *
+ * <p>
+ * Historically, in those countries which adopted the Gregorian calendar first,
+ * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
+ * this correctly.  Before the Gregorian cutover, {@code GregorianCalendar}
+ * implements the Julian calendar.  The only difference between the Gregorian
+ * and the Julian calendar is the leap year rule. The Julian calendar specifies
+ * leap years every four years, whereas the Gregorian calendar omits century
+ * years which are not divisible by 400.
+ *
+ * <p>
+ * {@code GregorianCalendar} implements <em>proleptic</em> Gregorian and
+ * Julian calendars. That is, dates are computed by extrapolating the current
+ * rules indefinitely far backward and forward in time. As a result,
+ * {@code GregorianCalendar} may be used for all years to generate
+ * meaningful and consistent results. However, dates obtained using
+ * {@code GregorianCalendar} are historically accurate only from March 1, 4
+ * AD onward, when modern Julian calendar rules were adopted.  Before this date,
+ * leap year rules were applied irregularly, and before 45 BC the Julian
+ * calendar did not even exist.
+ *
+ * <p>
+ * Prior to the institution of the Gregorian calendar, New Year's Day was
+ * March 25. To avoid confusion, this calendar always uses January 1. A manual
+ * adjustment may be made if desired for dates that are prior to the Gregorian
+ * changeover and which fall between January 1 and March 24.
+ *
+ * <h2><a id="week_and_year">Week Of Year and Week Year</a></h2>
+ *
+ * <p>Values calculated for the {@link Calendar#WEEK_OF_YEAR
+ * WEEK_OF_YEAR} field range from 1 to 53. The first week of a
+ * calendar year is the earliest seven day period starting on {@link
+ * Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at
+ * least {@link Calendar#getMinimalDaysInFirstWeek()
+ * getMinimalDaysInFirstWeek()} days from that year. It thus depends
+ * on the values of {@code getMinimalDaysInFirstWeek()}, {@code
+ * getFirstDayOfWeek()}, and the day of the week of January 1. Weeks
+ * between week 1 of one year and week 1 of the following year
+ * (exclusive) are numbered sequentially from 2 to 52 or 53 (except
+ * for year(s) involved in the Julian-Gregorian transition).
+ *
+ * <p>The {@code getFirstDayOfWeek()} and {@code
+ * getMinimalDaysInFirstWeek()} values are initialized using
+ * locale-dependent resources when constructing a {@code
+ * GregorianCalendar}. <a id="iso8601_compatible_setting">The week
+ * determination is compatible</a> with the ISO 8601 standard when {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4, which values are used in locales
+ * where the standard is preferred. These values can explicitly be set by
+ * calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and
+ * {@link Calendar#setMinimalDaysInFirstWeek(int)
+ * setMinimalDaysInFirstWeek()}.
+ *
+ * <p>A <a id="week_year"><em>week year</em></a> is in sync with a
+ * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last
+ * weeks (inclusive) have the same <em>week year</em> value.
+ * Therefore, the first and last days of a week year may have
+ * different calendar year values.
+ *
+ * <p>For example, January 1, 1998 is a Thursday. If {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible
+ * setting), then week 1 of 1998 starts on December 29, 1997, and ends
+ * on January 4, 1998. The week year is 1998 for the last three days
+ * of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is
+ * {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and
+ * ends on January 10, 1998; the first three days of 1998 then are
+ * part of week 53 of 1997 and their week year is 1997.
+ *
+ * <h3>Week Of Month</h3>
+ *
+ * <p>Values calculated for the {@code WEEK_OF_MONTH} field range from 0
+ * to 6.  Week 1 of a month (the days with <code>WEEK_OF_MONTH =
+ * 1</code>) is the earliest set of at least
+ * {@code getMinimalDaysInFirstWeek()} contiguous days in that month,
+ * ending on the day before {@code getFirstDayOfWeek()}.  Unlike
+ * week 1 of a year, week 1 of a month may be shorter than 7 days, need
+ * not start on {@code getFirstDayOfWeek()}, and will not include days of
+ * the previous month.  Days of a month before week 1 have a
+ * {@code WEEK_OF_MONTH} of 0.
+ *
+ * <p>For example, if {@code getFirstDayOfWeek()} is {@code SUNDAY}
+ * and {@code getMinimalDaysInFirstWeek()} is 4, then the first week of
+ * January 1998 is Sunday, January 4 through Saturday, January 10.  These days
+ * have a {@code WEEK_OF_MONTH} of 1.  Thursday, January 1 through
+ * Saturday, January 3 have a {@code WEEK_OF_MONTH} of 0.  If
+ * {@code getMinimalDaysInFirstWeek()} is changed to 3, then January 1
+ * through January 3 have a {@code WEEK_OF_MONTH} of 1.
+ *
+ * <h3>Default Fields Values</h3>
+ *
+ * <p>The {@code clear} method sets calendar field(s)
+ * undefined. {@code GregorianCalendar} uses the following
+ * default value for each calendar field if its value is undefined.
+ *
+ * <table class="striped" style="text-align: left; width: 66%;">
+ * <caption style="display:none">GregorianCalendar default field values</caption>
+ *   <thead>
+ *     <tr>
+ *       <th scope="col">
+ *          Field
+ *       </th>
+ *       <th scope="col">
+ *          Default Value
+ *       </th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code ERA}
+ *       </th>
+ *       <td>
+ *              {@code AD}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code YEAR}
+ *       </th>
+ *       <td>
+ *              {@code 1970}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code MONTH}
+ *       </th>
+ *       <td>
+ *              {@code JANUARY}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code DAY_OF_MONTH}
+ *       </th>
+ *       <td>
+ *              {@code 1}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code DAY_OF_WEEK}
+ *       </th>
+ *       <td>
+ *              {@code the first day of week}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code WEEK_OF_MONTH}
+ *       </th>
+ *       <td>
+ *              {@code 0}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code DAY_OF_WEEK_IN_MONTH}
+ *       </th>
+ *       <td>
+ *              {@code 1}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code AM_PM}
+ *       </th>
+ *       <td>
+ *              {@code AM}
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <th scope="row">
+ *              {@code HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND}
+ *       </th>
+ *       <td>
+ *              {@code 0}
+ *       </td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ * <br>Default values are not applicable for the fields not listed above.
+ *
+ * <p>
+ * <strong>Example:</strong>
+ * <blockquote>
+ * <pre>
+ * // get the supported ids for GMT-08:00 (Pacific Standard Time)
+ * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
+ * // if no ids were returned, something is wrong. get out.
+ * if (ids.length == 0)
+ *     System.exit(0);
+ *
+ *  // begin output
+ * System.out.println("Current Time");
+ *
+ * // create a Pacific Standard Time time zone
+ * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
+ *
+ * // set up rules for Daylight Saving Time
+ * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ *
+ * // create a GregorianCalendar with the Pacific Daylight time zone
+ * // and the current date and time
+ * Calendar calendar = new GregorianCalendar(pdt);
+ * Date trialTime = new Date();
+ * calendar.setTime(trialTime);
+ *
+ * // print out a bunch of interesting things
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
+ * System.out.println("DST_OFFSET: "
+ *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
+ * System.out.println("Current Time, with hour reset to 3");
+ * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
+ * calendar.set(Calendar.HOUR, 3);
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
+ * System.out.println("DST_OFFSET: "
+ *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
+ * </pre>
+ * </blockquote>
+ *
+ * @see          TimeZone
+ * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ * @since 1.1
+ */
+public class GregorianCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * The epoch is the number of days or milliseconds from some defined
+     * starting point. The epoch for java.util.Date is used here; that is,
+     * milliseconds from January 1, 1970 (Gregorian), midnight UTC.  Other
+     * epochs which are used are January 1, year 1 (Gregorian), which is day 1
+     * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
+     * day 1 of the Julian calendar.
+     *
+     * We implement the proleptic Julian and Gregorian calendars.  This means we
+     * implement the modern definition of the calendar even though the
+     * historical usage differs.  For example, if the Gregorian change is set
+     * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
+     * labels dates preceding the invention of the Gregorian calendar in 1582 as
+     * if the calendar existed then.
+     *
+     * Likewise, with the Julian calendar, we assume a consistent
+     * 4-year leap year rule, even though the historical pattern of
+     * leap years is irregular, being every 3 years from 45 BCE
+     * through 9 BCE, then every 4 years from 8 CE onwards, with no
+     * leap years in-between.  Thus date computations and functions
+     * such as isLeapYear() are not intended to be historically
+     * accurate.
+     */
+
+//////////////////
+// Class Variables
+//////////////////
+
+    /**
+     * Value of the {@code ERA} field indicating
+     * the period before the common era (before Christ), also known as BCE.
+     * The sequence of years at the transition from {@code BC} to {@code AD} is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int BC = 0;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the period before the common era, the same value as {@link #BC}.
+     *
+     * @see #CE
+     */
+    static final int BCE = 0;
+
+    /**
+     * Value of the {@code ERA} field indicating
+     * the common era (Anno Domini), also known as CE.
+     * The sequence of years at the transition from {@code BC} to {@code AD} is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int AD = 1;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the common era, the same value as {@link #AD}.
+     *
+     * @see #BCE
+     */
+    static final int CE = 1;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+    private static final int EPOCH_YEAR     = 1970;
+
+    static final int MONTH_LENGTH[]
+        = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
+    static final int LEAP_MONTH_LENGTH[]
+        = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+    private static final long ONE_WEEK   = 7*ONE_DAY;
+
+    /*
+     * <pre>
+     *                            Greatest       Least
+     * Field name        Minimum   Minimum     Maximum     Maximum
+     * ----------        -------   -------     -------     -------
+     * ERA                     0         0           1           1
+     * YEAR                    1         1   292269054   292278994
+     * MONTH                   0         0          11          11
+     * WEEK_OF_YEAR            1         1          52*         53
+     * WEEK_OF_MONTH           0         0           4*          6
+     * DAY_OF_MONTH            1         1          28*         31
+     * DAY_OF_YEAR             1         1         365*        366
+     * DAY_OF_WEEK             1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH    1         1           4*          6
+     * AM_PM                   0         0           1           1
+     * HOUR                    0         0          11          11
+     * HOUR_OF_DAY             0         0          23          23
+     * MINUTE                  0         0          59          59
+     * SECOND                  0         0          59          59
+     * MILLISECOND             0         0         999         999
+     * ZONE_OFFSET        -13:00    -13:00       14:00       14:00
+     * DST_OFFSET           0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on the Gregorian change date
+     */
+    static final int MIN_VALUES[] = {
+        BCE,            // ERA
+        1,              // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        CE,             // ERA
+        292269054,      // YEAR
+        DECEMBER,       // MONTH
+        52,             // WEEK_OF_YEAR
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        365,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        CE,             // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.1
+    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
+    @java.io.Serial
+    static final long serialVersionUID = -8125100834729963327L;
+
+    // Reference to the sun.util.calendar.Gregorian instance (singleton).
+    private static final Gregorian gcal =
+                                CalendarSystem.getGregorianCalendar();
+
+    // Reference to the JulianCalendar instance (singleton), set as needed. See
+    // getJulianCalendarSystem().
+    private static JulianCalendar jcal;
+
+    // JulianCalendar eras. See getJulianCalendarSystem().
+    private static Era[] jeras;
+
+    // The default value of gregorianCutover.
+    static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
+
+/////////////////////
+// Instance Variables
+/////////////////////
+
+    /**
+     * The point at which the Gregorian calendar rules are used, measured in
+     * milliseconds from the standard epoch.  Default is October 15, 1582
+     * (Gregorian) 00:00:00 UTC or -12219292800000L.  For this value, October 4,
+     * 1582 (Julian) is followed by October 15, 1582 (Gregorian).  This
+     * corresponds to Julian day number 2299161.
+     * @serial
+     */
+    private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
+
+    /**
+     * The fixed date of the gregorianCutover.
+     */
+    private transient long gregorianCutoverDate =
+        (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
+
+    /**
+     * The normalized year of the gregorianCutover in Gregorian, with
+     * 0 representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYear = 1582;
+
+    /**
+     * The normalized year of the gregorianCutover in Julian, with 0
+     * representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYearJulian = 1582;
+
+    /**
+     * gdate always has a sun.util.calendar.Gregorian.Date instance to
+     * avoid overhead of creating it. The assumption is that most
+     * applications will need only Gregorian calendar calculations.
+     */
+    private transient BaseCalendar.Date gdate;
+
+    /**
+     * Reference to either gdate or a JulianCalendar.Date
+     * instance. After calling complete(), this value is guaranteed to
+     * be set.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    /**
+     * The CalendarSystem used to calculate the date in cdate. After
+     * calling complete(), this value is guaranteed to be set and
+     * consistent with the cdate value.
+     */
+    private transient BaseCalendar calsys;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the DST saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+///////////////
+// Constructors
+///////////////
+
+    /**
+     * Constructs a default {@code GregorianCalendar} using the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     */
+    public GregorianCalendar() {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the given time zone.
+     */
+    public GregorianCalendar(TimeZone zone) {
+        this(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} based on the current time
+     * in the default time zone with the given locale.
+     *
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(Locale aLocale) {
+        this(TimeZone.getDefaultRef(), aLocale);
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} with the given date set
+     * in the default time zone with the default locale.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field in the calendar.
+     * @param month the value used to set the {@code MONTH} calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the {@code DAY_OF_MONTH} calendar field in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth) {
+        this(year, month, dayOfMonth, 0, 0, 0, 0);
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field in the calendar.
+     * @param month the value used to set the {@code MONTH} calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the {@code DAY_OF_MONTH} calendar field in the calendar.
+     * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field
+     * in the calendar.
+     * @param minute the value used to set the {@code MINUTE} calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute) {
+        this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
+    }
+
+    /**
+     * Constructs a GregorianCalendar with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field in the calendar.
+     * @param month the value used to set the {@code MONTH} calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the {@code DAY_OF_MONTH} calendar field in the calendar.
+     * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field
+     * in the calendar.
+     * @param minute the value used to set the {@code MINUTE} calendar field
+     * in the calendar.
+     * @param second the value used to set the {@code SECOND} calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute, int second) {
+        this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
+    }
+
+    /**
+     * Constructs a {@code GregorianCalendar} with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the {@code YEAR} calendar field in the calendar.
+     * @param month the value used to set the {@code MONTH} calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the {@code DAY_OF_MONTH} calendar field in the calendar.
+     * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field
+     * in the calendar.
+     * @param minute the value used to set the {@code MINUTE} calendar field
+     * in the calendar.
+     * @param second the value used to set the {@code SECOND} calendar field
+     * in the calendar.
+     * @param millis the value used to set the {@code MILLISECOND} calendar field
+     */
+    GregorianCalendar(int year, int month, int dayOfMonth,
+                      int hourOfDay, int minute, int second, int millis) {
+        super();
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+        this.set(YEAR, year);
+        this.set(MONTH, month);
+        this.set(DAY_OF_MONTH, dayOfMonth);
+
+        // Set AM_PM and HOUR here to set their stamp values before
+        // setting HOUR_OF_DAY (6178071).
+        if (hourOfDay >= 12 && hourOfDay <= 23) {
+            // If hourOfDay is a valid PM hour, set the correct PM values
+            // so that it won't throw an exception in case it's set to
+            // non-lenient later.
+            this.internalSet(AM_PM, PM);
+            this.internalSet(HOUR, hourOfDay - 12);
+        } else {
+            // The default value for AM_PM is AM.
+            // We don't care any out of range value here for leniency.
+            this.internalSet(HOUR, hourOfDay);
+        }
+        // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
+        setFieldsComputed(HOUR_MASK|AM_PM_MASK);
+
+        this.set(HOUR_OF_DAY, hourOfDay);
+        this.set(MINUTE, minute);
+        this.set(SECOND, second);
+        // should be changed to set() when this constructor is made
+        // public.
+        this.internalSet(MILLISECOND, millis);
+    }
+
+    /**
+     * Constructs an empty GregorianCalendar.
+     *
+     * @param zone    the given time zone
+     * @param locale  the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    GregorianCalendar(TimeZone zone, Locale locale, boolean flag) {
+        super(zone, locale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+    }
+
+    // BEGIN Android-added: Constructor.
+    GregorianCalendar(long milliseconds) {
+        this();
+        setTimeInMillis(milliseconds);
+    }
+    // END Android-added: Constructor.
+
+/////////////////
+// Public methods
+/////////////////
+
+    /**
+     * Sets the {@code GregorianCalendar} change date. This is the point when the switch
+     * from Julian dates to Gregorian dates occurred. Default is October 15,
+     * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
+     * <p>
+     * To obtain a pure Julian calendar, set the change date to
+     * {@code Date(Long.MAX_VALUE)}.  To obtain a pure Gregorian calendar,
+     * set the change date to {@code Date(Long.MIN_VALUE)}.
+     *
+     * @param date the given Gregorian cutover date.
+     */
+    public void setGregorianChange(Date date) {
+        long cutoverTime = date.getTime();
+        if (cutoverTime == gregorianCutover) {
+            return;
+        }
+        // Before changing the cutover date, make sure to have the
+        // time of this calendar.
+        complete();
+        setGregorianChange(cutoverTime);
+    }
+
+    private void setGregorianChange(long cutoverTime) {
+        gregorianCutover = cutoverTime;
+        gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
+                                + EPOCH_OFFSET;
+
+        // To provide the "pure" Julian calendar as advertised.
+        // Strictly speaking, the last millisecond should be a
+        // Gregorian date. However, the API doc specifies that setting
+        // the cutover date to Long.MAX_VALUE will make this calendar
+        // a pure Julian calendar. (See 4167995)
+        if (cutoverTime == Long.MAX_VALUE) {
+            gregorianCutoverDate++;
+        }
+
+        BaseCalendar.Date d = getGregorianCutoverDate();
+
+        // Set the cutover year (in the Gregorian year numbering)
+        gregorianCutoverYear = d.getYear();
+
+        BaseCalendar julianCal = getJulianCalendarSystem();
+        d = (BaseCalendar.Date) julianCal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        julianCal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
+        gregorianCutoverYearJulian = d.getNormalizedYear();
+
+        if (time < gregorianCutover) {
+            // The field values are no longer valid under the new
+            // cutover date.
+            setUnnormalized();
+        }
+    }
+
+    /**
+     * Gets the Gregorian Calendar change date.  This is the point when the
+     * switch from Julian dates to Gregorian dates occurred. Default is
+     * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
+     * calendar.
+     *
+     * @return the Gregorian cutover date for this {@code GregorianCalendar} object.
+     */
+    public final Date getGregorianChange() {
+        return new Date(gregorianCutover);
+    }
+
+    /**
+     * Determines if the given year is a leap year. Returns {@code true} if
+     * the given year is a leap year. To specify BC year numbers,
+     * {@code 1 - year number} must be given. For example, year BC 4 is
+     * specified as -3.
+     *
+     * @param year the given year.
+     * @return {@code true} if the given year is a leap year; {@code false} otherwise.
+     */
+    public boolean isLeapYear(int year) {
+        if ((year & 3) != 0) {
+            return false;
+        }
+
+        if (year > gregorianCutoverYear) {
+            return (year%100 != 0) || (year%400 == 0); // Gregorian
+        }
+        if (year < gregorianCutoverYearJulian) {
+            return true; // Julian
+        }
+        boolean gregorian;
+        // If the given year is the Gregorian cutover year, we need to
+        // determine which calendar system to be applied to February in the year.
+        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+            BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
+            gregorian = d.getMonth() < BaseCalendar.MARCH;
+        } else {
+            gregorian = year == gregorianCutoverYear;
+        }
+        return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
+    }
+
+    /**
+     * Returns {@code "gregory"} as the calendar type.
+     *
+     * @return {@code "gregory"}
+     * @since 1.8
+     */
+    @Override
+    public String getCalendarType() {
+        return "gregory";
+    }
+
+    /**
+     * Compares this {@code GregorianCalendar} to the specified
+     * {@code Object}. The result is {@code true} if and
+     * only if the argument is a {@code GregorianCalendar} object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * {@code Calendar} parameters and Gregorian change date as
+     * this object.
+     *
+     * @param obj the object to compare with.
+     * @return {@code true} if this object is equal to {@code obj};
+     * {@code false} otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof GregorianCalendar &&
+            super.equals(obj) &&
+            gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
+    }
+
+    /**
+     * Generates the hash code for this {@code GregorianCalendar} object.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ (int)gregorianCutoverDate;
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of {@code field}
+     * after the call minus the value of {@code field} before the
+     * call is {@code amount}, modulo any overflow that has occurred in
+     * {@code field}. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * {@code field} is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. {@code HOUR} is a smaller field than
+     * {@code DAY_OF_MONTH}. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @throws    IllegalArgumentException if {@code field} is
+     * {@code ZONE_OFFSET}, {@code DST_OFFSET}, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    @Override
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            int year = internalGet(YEAR);
+            if (internalGetEra() == CE) {
+                year += amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 BCE.
+                    set(ERA, BCE);
+                }
+            }
+            else { // era == BCE
+                year -= amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 CE
+                    set(ERA, CE);
+                }
+            }
+            pinDayOfMonth();
+        } else if (field == MONTH) {
+            int month = internalGet(MONTH) + amount;
+            int year = internalGet(YEAR);
+            int y_amount;
+
+            if (month >= 0) {
+                y_amount = month/12;
+            } else {
+                y_amount = (month+1)/12 - 1;
+            }
+            if (y_amount != 0) {
+                if (internalGetEra() == CE) {
+                    year += y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 BCE
+                        set(ERA, BCE);
+                    }
+                }
+                else { // era == BCE
+                    year -= y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 CE
+                        set(ERA, CE);
+                    }
+                }
+            }
+
+            if (month >= 0) {
+                set(MONTH,  month % 12);
+            } else {
+                // month < 0
+                month %= 12;
+                if (month < 0) {
+                    month += 12;
+                }
+                set(MONTH, JANUARY + month);
+            }
+            pinDayOfMonth();
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            }
+            if (era > 1) {
+                era = 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to minutes
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to seconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = getCurrentFixedDate();
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            // BEGIN Android-changed: time zone related calculation via helper methods.
+            // Calculate the time in the UTC time zone.
+            long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+            // Neither of the time zone related fields are relevant because they have not been
+            // set since the call to complete() above.
+            int tzMask = 0;
+
+            // Adjust the time to account for zone and daylight savings time offset.
+            long millis = adjustForZoneAndDaylightSavingsTime(tzMask, utcTime, getZone());
+
+            // Update the time and recompute the fields.
+            setTimeInMillis(millis);
+            // END Android-changed: time zone related calculation via helper methods.
+        }
+    }
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields.
+     * <p>
+     * <em>Example</em>: Consider a {@code GregorianCalendar}
+     * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
+     * sets the calendar to January 31, 1999.  The {@code YEAR} field is unchanged
+     * because it is a larger field than {@code MONTH}.</p>
+     *
+     * @param up indicates if the value of the specified calendar field is to be
+     * rolled up or rolled down. Use {@code true} if rolling up, {@code false} otherwise.
+     * @throws    IllegalArgumentException if {@code field} is
+     * {@code ZONE_OFFSET}, {@code DST_OFFSET}, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    @Override
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * <p>
+     * <em>Example</em>: Consider a {@code GregorianCalendar}
+     * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
+     * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
+     * {@code GregorianCalendar}, the {@code DAY_OF_MONTH} field cannot
+     * be 31 in the month April. {@code DAY_OF_MONTH} is set to the closest possible
+     * value, 30. The {@code YEAR} field maintains the value of 1999 because it
+     * is a larger field than {@code MONTH}.
+     * <p>
+     * <em>Example</em>: Consider a {@code GregorianCalendar}
+     * originally set to Sunday June 6, 1999. Calling
+     * {@code roll(Calendar.WEEK_OF_MONTH, -1)} sets the calendar to
+     * Tuesday June 1, 1999, whereas calling
+     * {@code add(Calendar.WEEK_OF_MONTH, -1)} sets the calendar to
+     * Sunday May 30, 1999. This is because the roll rule imposes an
+     * additional constraint: The {@code MONTH} must not change when the
+     * {@code WEEK_OF_MONTH} is rolled. Taken together with add rule 1,
+     * the resultant date must be between Tuesday June 1 and Saturday June
+     * 5. According to add rule 2, the {@code DAY_OF_WEEK}, an invariant
+     * when changing the {@code WEEK_OF_MONTH}, is set to Tuesday, the
+     * closest possible value to Sunday (where Sunday is the first day of the
+     * week).</p>
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to {@code field}.
+     * @throws    IllegalArgumentException if {@code field} is
+     * {@code ZONE_OFFSET}, {@code DST_OFFSET}, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     * @since 1.2
+     */
+    @Override
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case AM_PM:
+        case ERA:
+        case YEAR:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed minima
+            // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
+            // fields are complicated, since the range within they must roll
+            // varies depending on the date.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int rolledValue = getRolledValue(internalGet(field), amount, min, max);
+                int hourOfDay = rolledValue;
+                if (field == HOUR && internalGet(AM_PM) == PM) {
+                    hourOfDay += 12;
+                }
+
+                // Create the current date/time value to perform wall-clock-based
+                // roll.
+                CalendarDate d = calsys.getCalendarDate(time, getZone());
+                d.setHours(hourOfDay);
+                time = calsys.getTime(d);
+
+                // If we stay on the same wall-clock time, try the next or previous hour.
+                if (internalGet(HOUR_OF_DAY) == d.getHours()) {
+                    hourOfDay = getRolledValue(rolledValue, amount > 0 ? +1 : -1, min, max);
+                    if (field == HOUR && internalGet(AM_PM) == PM) {
+                        hourOfDay += 12;
+                    }
+                    d.setHours(hourOfDay);
+                    time = calsys.getTime(d);
+                }
+                // Get the new hourOfDay value which might have changed due to a DST transition.
+                hourOfDay = d.getHours();
+                // Update the hour related fields
+                internalSet(HOUR_OF_DAY, hourOfDay);
+                internalSet(AM_PM, hourOfDay / 12);
+                internalSet(HOUR, hourOfDay % 12);
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int mon = (internalGet(MONTH) + amount) % 12;
+                    if (mon < 0) {
+                        mon += 12;
+                    }
+                    set(MONTH, mon);
+
+                    // Keep the day of month in the range.  We don't want to spill over
+                    // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
+                    // mar3.
+                    int monthLen = monthLength(mon);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                } else {
+                    // We need to take care of different lengths in
+                    // year and month due to the cutover.
+                    int yearLength = getActualMaximum(MONTH) + 1;
+                    int mon = (internalGet(MONTH) + amount) % yearLength;
+                    if (mon < 0) {
+                        mon += yearLength;
+                    }
+                    set(MONTH, mon);
+                    int monthLen = getActualMaximum(DAY_OF_MONTH);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = cdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isCutoverYear(y)) {
+                    int weekYear = getWeekYear();
+                    if (weekYear == y) {
+                        // If the new value is in between min and max
+                        // (exclusive), then we can use the value.
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+                        long fd = getCurrentFixedDate();
+                        // Make sure that the min week has the current DAY_OF_WEEK
+                        // in the calendar year
+                        long day1 = fd - (7 * (woy - min));
+                        if (calsys.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+
+                        // Make sure the same thing for the max week
+                        fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                        if (calsys.getYearFromFixedDate(fd) != y) {
+                            max--;
+                        }
+                    } else {
+                        // When WEEK_OF_YEAR and YEAR are out of sync,
+                        // adjust woy and amount to stay in the calendar year.
+                        if (weekYear > y) {
+                            if (amount < 0) {
+                                amount++;
+                            }
+                            woy = max;
+                        } else {
+                            if (amount > 0) {
+                                amount -= woy - max;
+                            }
+                            woy = min;
+                        }
+                    }
+                    set(field, getRolledValue(woy, amount, min, max));
+                    return;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                BaseCalendar cal;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    cal = getCutoverCalendarSystem();
+                } else if (y == gregorianCutoverYear) {
+                    cal = gcal;
+                } else {
+                    cal = getJulianCalendarSystem();
+                }
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                if (cal.getYearFromFixedDate(day1) != y) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                if (cal.getYearFromFixedDate(fd) != y) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
+                // dow: relative day of week from first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = getCurrentFixedDate();
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isCutoverYear) {
+                    month1 = getFixedDateMonth1(cdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = calsys.getMonthLength(cdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = BaseCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                           getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                int dayOfMonth;
+                if (isCutoverYear) {
+                    // If we are in the cutover year, convert nfd to
+                    // its calendar date and use dayOfMonth.
+                    BaseCalendar.Date d = getCalendarDate(nfd);
+                    dayOfMonth = d.getDayOfMonth();
+                } else {
+                    dayOfMonth = (int)(nfd - month1) + 1;
+                }
+                set(DAY_OF_MONTH, dayOfMonth);
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    max = calsys.getMonthLength(cdate);
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
+                BaseCalendar.Date d = getCalendarDate(month1 + value);
+                assert d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
+                int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
+                BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the cutover year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = getCurrentFixedDate();
+                long dowFirst = BaseCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                BaseCalendar.Date d = getCalendarDate(fd);
+                set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after normalized, min should be 1.
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = calsys.getMonthLength(cdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                cal.getCalendarDateFromFixedDate(d, fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * {@code GregorianCalendar} instance. The minimum value is
+     * defined as the smallest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * {@code GregorianCalendar} instance. The maximum value is
+     * defined as the largest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMaximum(int field) {
+        switch (field) {
+            case MONTH, DAY_OF_MONTH, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, YEAR -> {
+                // On or after Gregorian 200-3-1, Julian and Gregorian
+                // calendar dates are the same or Gregorian dates are
+                // larger (i.e., there is a "gap") after 300-3-1.
+                if (gregorianCutoverYear > 200) {
+                    break;
+                }
+                // There might be "overlapping" dates.
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover - 1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.max(MAX_VALUES[field], Math.max(v1, v2));
+            }
+        }
+        return MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this {@code GregorianCalendar} instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getGreatestMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            BaseCalendar.Date d = getGregorianCutoverDate();
+            long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
+            d = getCalendarDate(mon1);
+            return Math.max(MIN_VALUES[field], d.getDayOfMonth());
+        }
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this {@code GregorianCalendar} instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getLeastMaximum(int field) {
+        switch (field) {
+            case MONTH, DAY_OF_MONTH, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, YEAR -> {
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover - 1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
+            }
+        }
+        return LEAST_MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * <p>For example, if the Gregorian change date is January 10,
+     * 1970 and the date of this {@code GregorianCalendar} is
+     * January 20, 1970, the actual minimum value of the
+     * {@code DAY_OF_MONTH} field is 10 because the previous date
+     * of January 10, 1970 is December 27, 1996 (in the Julian
+     * calendar). Therefore, December 28, 1969 to January 9, 1970
+     * don't exist.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this {@code GregorianCalendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            GregorianCalendar gc = getNormalizedCalendar();
+            int year = gc.cdate.getNormalizedYear();
+            if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
+                long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
+                BaseCalendar.Date d = getCalendarDate(month1);
+                return d.getDayOfMonth();
+            }
+        }
+        return getMinimum(field);
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is February 1, 2004,
+     * the actual maximum value of the {@code DAY_OF_MONTH} field
+     * is 29 because 2004 is a leap year, and if the date of this
+     * instance is February 1, 2005, it's 28.
+     *
+     * <p>This method calculates the maximum value of {@link
+     * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link
+     * Calendar#YEAR YEAR} (calendar year) value, not the <a
+     * href="#week_year">week year</a>. Call {@link
+     * #getWeeksInWeekYear()} to get the maximum value of {@code
+     * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this {@code GregorianCalendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        GregorianCalendar gc = getNormalizedCalendar();
+        BaseCalendar.Date date = gc.cdate;
+        BaseCalendar cal = gc.calsys;
+        int normalizedYear = date.getNormalizedYear();
+
+        int value = -1;
+        switch (field) {
+            case MONTH -> {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = DECEMBER;
+                    break;
+                }
+
+                // January 1 of the next year may or may not exist.
+                long nextJan1;
+                do {
+                    nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
+                } while (nextJan1 < gregorianCutoverDate);
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
+                value = d.getMonth() - 1;
+            }
+            case DAY_OF_MONTH -> {
+                value = cal.getMonthLength(date);
+                if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
+                    break;
+                }
+
+                // Handle cutover year.
+                long fd = gc.getCurrentFixedDate();
+                if (fd >= gregorianCutoverDate) {
+                    break;
+                }
+                int monthLength = gc.actualMonthLength();
+                long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
+                // Convert the fixed date to its calendar date.
+                BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
+                value = d.getDayOfMonth();
+            }
+            case DAY_OF_YEAR -> {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = cal.getYearLength(date);
+                    break;
+                }
+
+                // Handle cutover year.
+                long jan1;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    BaseCalendar cocal = gc.getCutoverCalendarSystem();
+                    jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
+                } else if (normalizedYear == gregorianCutoverYearJulian) {
+                    jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
+                } else {
+                    jan1 = gregorianCutoverDate;
+                }
+                // January 1 of the next year may or may not exist.
+                long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
+                if (nextJan1 < gregorianCutoverDate) {
+                    nextJan1 = gregorianCutoverDate;
+                }
+                assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                value = (int)(nextJan1 - jan1);
+            }
+            case WEEK_OF_YEAR -> {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    // Get the day of week of January 1 of the year
+                    CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    // Normalize the day of week with the firstDayOfWeek value
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    value = 52;
+                    int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                    if ((magic == 6) ||
+                        (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                        value++;
+                    }
+                    break;
+                }
+
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+                gc.set(DAY_OF_YEAR, maxDayOfYear);
+                value = gc.get(WEEK_OF_YEAR);
+                if (internalGet(YEAR) != gc.getWeekYear()) {
+                    gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
+                    value = gc.get(WEEK_OF_YEAR);
+                }
+            }
+            case WEEK_OF_MONTH -> {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    CalendarDate d = cal.newCalendarDate(null);
+                    d.setDate(date.getYear(), date.getMonth(), 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    int monthLength = cal.getMonthLength(d);
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                    value = 3;
+                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                        value++;
+                    }
+                    monthLength -= nDaysFirstWeek + 7 * 3;
+                    if (monthLength > 0) {
+                        value++;
+                        if (monthLength > 7) {
+                            value++;
+                        }
+                    }
+                    break;
+                }
+
+                // Cutover year handling
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int y = gc.internalGet(YEAR);
+                int m = gc.internalGet(MONTH);
+                do {
+                    value = gc.get(WEEK_OF_MONTH);
+                    gc.add(WEEK_OF_MONTH, +1);
+                } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
+            }
+            case DAY_OF_WEEK_IN_MONTH -> {
+                // may be in the Gregorian cutover month
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                    ndays = cal.getMonthLength(d);
+                    d.setDayOfMonth(1);
+                    cal.normalize(d);
+                    dow1 = d.getDayOfWeek();
+                } else {
+                    // Let a cloned GregorianCalendar take care of the cutover cases.
+                    if (gc == this) {
+                        gc = (GregorianCalendar) clone();
+                    }
+                    ndays = gc.actualMonthLength();
+                    gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
+                    dow1 = gc.get(DAY_OF_WEEK);
+                }
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                value = (ndays + 6) / 7;
+            }
+            case YEAR -> {
+                /* The year computation is no different, in principle, from the
+                 * others, however, the range of possible maxima is large.  In
+                 * addition, the way we know we've exceeded the range is different.
+                 * For these reasons, we use the special case code below to handle
+                 * this field.
+                 *
+                 * The actual maxima for YEAR depend on the type of calendar:
+                 *
+                 *     Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
+                 *     Julian    = Dec  2, 292269055 BCE - Jan  3, 292272993 CE
+                 *     Hybrid    = Dec  2, 292269055 BCE - Aug 17, 292278994 CE
+                 *
+                 * We know we've exceeded the maximum when either the month, date,
+                 * time, or era changes in response to setting the year.  We don't
+                 * check for month, date, and time here because the year and era are
+                 * sufficient to detect an invalid year setting.  NOTE: If code is
+                 * added to check the month and date in the future for some reason,
+                 * Feb 29 must be allowed to shift to Mar 1 when setting the year.
+                 */
+                if (gc == this) {
+                    gc = (GregorianCalendar) clone();
+                }
+
+                // Calculate the millisecond offset from the beginning
+                // of the year of this calendar and adjust the max
+                // year value if we are beyond the limit in the max
+                // year.
+                long current = gc.getYearOffsetInMillis();
+
+                if (gc.internalGetEra() == CE) {
+                    gc.setTimeInMillis(Long.MAX_VALUE);
+                    value = gc.get(YEAR);
+                    long maxEnd = gc.getYearOffsetInMillis();
+                    if (current > maxEnd) {
+                        value--;
+                    }
+                } else {
+                    CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
+                        gcal : getJulianCalendarSystem();
+                    CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
+                    maxEnd *= 60;
+                    maxEnd += d.getMinutes();
+                    maxEnd *= 60;
+                    maxEnd += d.getSeconds();
+                    maxEnd *= 1000;
+                    maxEnd += d.getMillis();
+                    value = d.getYear();
+                    if (value <= 0) {
+                        assert mincal == gcal;
+                        value = 1 - value;
+                    }
+                    if (current < maxEnd) {
+                        value--;
+                    }
+                }
+            }
+            default -> throw new ArrayIndexOutOfBoundsException(field);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of this
+     * year. This Calendar object must have been normalized.
+     */
+    private long getYearOffsetInMillis() {
+        long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
+        t += internalGet(HOUR_OF_DAY);
+        t *= 60;
+        t += internalGet(MINUTE);
+        t *= 60;
+        t += internalGet(SECOND);
+        t *= 1000;
+        return t + internalGet(MILLISECOND) -
+            (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
+    }
+
+    @Override
+    public Object clone()
+    {
+        GregorianCalendar other = (GregorianCalendar) super.clone();
+
+        other.gdate = (BaseCalendar.Date) gdate.clone();
+        if (cdate != null) {
+            if (cdate != gdate) {
+                other.cdate = (BaseCalendar.Date) cdate.clone();
+            } else {
+                other.cdate = other.gdate;
+            }
+        }
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    @Override
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+        return zone;
+    }
+
+    @Override
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+    }
+
+    /**
+     * Returns {@code true} indicating this {@code GregorianCalendar}
+     * supports week dates.
+     *
+     * @return {@code true} (always)
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    @Override
+    public final boolean isWeekDateSupported() {
+        return true;
+    }
+
+    /**
+     * Returns the <a href="#week_year">week year</a> represented by this
+     * {@code GregorianCalendar}. The dates in the weeks between 1 and the
+     * maximum week number of the week year have the same week year value
+     * that may be one year before or after the {@link Calendar#YEAR YEAR}
+     * (calendar year) value.
+     *
+     * <p>This method calls {@link Calendar#complete()} before
+     * calculating the week year.
+     *
+     * @return the week year represented by this {@code GregorianCalendar}.
+     *         If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is
+     *         represented by 0 or a negative number: BC 1 is 0, BC 2
+     *         is -1, BC 3 is -2, and so on.
+     * @throws IllegalArgumentException
+     *         if any of the calendar fields is invalid in non-lenient mode.
+     * @see #isWeekDateSupported()
+     * @see #getWeeksInWeekYear()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public int getWeekYear() {
+        int year = get(YEAR); // implicitly calls complete()
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+
+        // Fast path for the Gregorian calendar years that are never
+        // affected by the Julian-Gregorian transition
+        if (year > gregorianCutoverYear + 1) {
+            int weekOfYear = internalGet(WEEK_OF_YEAR);
+            if (internalGet(MONTH) == JANUARY) {
+                if (weekOfYear >= 52) {
+                    --year;
+                }
+            } else {
+                if (weekOfYear == 1) {
+                    ++year;
+                }
+            }
+            return year;
+        }
+
+        // General (slow) path
+        int dayOfYear = internalGet(DAY_OF_YEAR);
+        int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+        int minimalDays = getMinimalDaysInFirstWeek();
+
+        // Quickly check the possibility of year adjustments before
+        // cloning this GregorianCalendar.
+        if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
+            return year;
+        }
+
+        // Create a clone to work on the calculation
+        GregorianCalendar cal = (GregorianCalendar) clone();
+        cal.setLenient(true);
+        // Use GMT so that intermediate date calculations won't
+        // affect the time of day fields.
+        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+        // Go to the first day of the year, which is usually January 1.
+        cal.set(DAY_OF_YEAR, 1);
+        cal.complete();
+
+        // Get the first day of the first day-of-week in the year.
+        int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+        if (delta != 0) {
+            if (delta < 0) {
+                delta += 7;
+            }
+            cal.add(DAY_OF_YEAR, delta);
+        }
+        int minDayOfYear = cal.get(DAY_OF_YEAR);
+        if (dayOfYear < minDayOfYear) {
+            if (minDayOfYear <= minimalDays) {
+                --year;
+            }
+        } else {
+            cal.set(YEAR, year + 1);
+            cal.set(DAY_OF_YEAR, 1);
+            cal.complete();
+            int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+            if (del != 0) {
+                if (del < 0) {
+                    del += 7;
+                }
+                cal.add(DAY_OF_YEAR, del);
+            }
+            minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
+            if (minDayOfYear == 0) {
+                minDayOfYear = 7;
+            }
+            if (minDayOfYear >= minimalDays) {
+                int days = maxDayOfYear - dayOfYear + 1;
+                if (days <= (7 - minDayOfYear)) {
+                    ++year;
+                }
+            }
+        }
+        return year;
+    }
+
+    /**
+     * Sets this {@code GregorianCalendar} to the date given by the
+     * date specifiers - <a href="#week_year">{@code weekYear}</a>,
+     * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
+     * follows the <a href="#week_and_year">{@code WEEK_OF_YEAR}
+     * numbering</a>.  The {@code dayOfWeek} value must be one of the
+     * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link
+     * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}.
+     *
+     * <p>Note that the numeric day-of-week representation differs from
+     * the ISO 8601 standard, and that the {@code weekOfYear}
+     * numbering is compatible with the standard when {@code
+     * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+     * getMinimalDaysInFirstWeek()} is 4.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and the instant of time value are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year
+     * range in {@code weekYear}, the {@code weekYear}
+     * and {@code weekOfYear} values are adjusted in lenient
+     * mode, or an {@code IllegalArgumentException} is thrown in
+     * non-lenient mode.
+     *
+     * @param weekYear    the week year
+     * @param weekOfYear  the week number based on {@code weekYear}
+     * @param dayOfWeek   the day of week value: one of the constants
+     *                    for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field:
+     *                    {@link Calendar#SUNDAY SUNDAY}, ...,
+     *                    {@link Calendar#SATURDAY SATURDAY}.
+     * @throws    IllegalArgumentException
+     *            if any of the given date specifiers is invalid,
+     *            or if any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @see GregorianCalendar#isWeekDateSupported()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
+            throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
+        }
+
+        // To avoid changing the time of day fields by date
+        // calculations, use a clone with the GMT time zone.
+        GregorianCalendar gc = (GregorianCalendar) clone();
+        gc.setLenient(true);
+        int era = gc.get(ERA);
+        gc.clear();
+        gc.setTimeZone(TimeZone.getTimeZone("GMT"));
+        gc.set(ERA, era);
+        gc.set(YEAR, weekYear);
+        gc.set(WEEK_OF_YEAR, 1);
+        gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
+        int days = dayOfWeek - getFirstDayOfWeek();
+        if (days < 0) {
+            days += 7;
+        }
+        days += 7 * (weekOfYear - 1);
+        if (days != 0) {
+            gc.add(DAY_OF_YEAR, days);
+        } else {
+            gc.complete();
+        }
+
+        if (!isLenient() &&
+            (gc.getWeekYear() != weekYear
+             || gc.internalGet(WEEK_OF_YEAR) != weekOfYear
+             || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) {
+            throw new IllegalArgumentException();
+        }
+
+        set(ERA, gc.internalGet(ERA));
+        set(YEAR, gc.internalGet(YEAR));
+        set(MONTH, gc.internalGet(MONTH));
+        set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
+
+        // to avoid throwing an IllegalArgumentException in
+        // non-lenient, set WEEK_OF_YEAR internally
+        internalSet(WEEK_OF_YEAR, weekOfYear);
+        complete();
+    }
+
+    /**
+     * Returns the number of weeks in the <a href="#week_year">week year</a>
+     * represented by this {@code GregorianCalendar}.
+     *
+     * <p>For example, if this {@code GregorianCalendar}'s date is
+     * December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO
+     * 8601 compatible setting</a>, this method will return 53 for the
+     * period: December 29, 2008 to January 3, 2010 while {@link
+     * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return
+     * 52 for the period: December 31, 2007 to December 28, 2008.
+     *
+     * @return the number of weeks in the week year.
+     * @see Calendar#WEEK_OF_YEAR
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    @Override
+    public int getWeeksInWeekYear() {
+        GregorianCalendar gc = getNormalizedCalendar();
+        int weekYear = gc.getWeekYear();
+        if (weekYear == gc.internalGet(YEAR)) {
+            return gc.getActualMaximum(WEEK_OF_YEAR);
+        }
+
+        // Use the 2nd week for calculating the max of WEEK_OF_YEAR
+        if (gc == this) {
+            gc = (GregorianCalendar) gc.clone();
+        }
+        gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
+        return gc.getActualMaximum(WEEK_OF_YEAR);
+    }
+
+/////////////////////////////
+// Time => Fields computation
+/////////////////////////////
+
+    /**
+     * The fixed date corresponding to gdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown. Currently,
+     * Julian calendar dates are not cached.
+     */
+    private transient long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * {@code complete} method.
+     *
+     * @see Calendar#complete
+     */
+    @Override
+    protected void computeFields() {
+        int mask;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            // We have to call computTime in case calsys == null in
+            // order to set calsys and cdate. (6263644)
+            if (fieldMask != 0 || calsys == null) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (tz instanceof ZoneInfo) {
+                // BEGIN Android-changed: use libcore.util.ZoneInfo.
+                // The method name to get offsets differs from sun.util.calendar.ZoneInfo
+                // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+                ZoneInfo zoneInfo = (ZoneInfo) tz;
+                zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
+                // END Android-changed: use libcore.util.ZoneInfo.
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        int era = CE;
+        int year;
+        if (fixedDate >= gregorianCutoverDate) {
+            // Handle Gregorian dates.
+            assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
+                        : "cache control: not normalized";
+            assert cachedFixedDate == Long.MIN_VALUE ||
+                   gcal.getFixedDate(gdate.getNormalizedYear(),
+                                          gdate.getMonth(),
+                                          gdate.getDayOfMonth(), gdate)
+                                == cachedFixedDate
+                        : "cache control: inconsictency" +
+                          ", cachedFixedDate=" + cachedFixedDate +
+                          ", computed=" +
+                          gcal.getFixedDate(gdate.getNormalizedYear(),
+                                                 gdate.getMonth(),
+                                                 gdate.getDayOfMonth(),
+                                                 gdate) +
+                          ", date=" + gdate;
+
+            // See if we can use gdate to avoid date calculation.
+            if (fixedDate != cachedFixedDate) {
+                gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
+                cachedFixedDate = fixedDate;
+            }
+
+            year = gdate.getYear();
+            if (year <= 0) {
+                year = 1 - year;
+                era = BCE;
+            }
+            calsys = gcal;
+            cdate = gdate;
+            assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
+        } else {
+            // Handle Julian calendar dates.
+            calsys = getJulianCalendarSystem();
+            cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
+            jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
+            Era e = cdate.getEra();
+            if (e == jeras[0]) {
+                era = BCE;
+            }
+            year = cdate.getYear();
+        }
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  cdate.getMonth() - 1; // 0-based
+        int dayOfMonth = cdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = cdate.getNormalizedYear();
+            long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
+            int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
+            int cutoverGap = 0;
+            int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+            int relativeDayOfMonth = dayOfMonth - 1;
+
+            // If we are in the cutover year, we need some special handling.
+            if (normalizedYear == cutoverYear) {
+                // Need to take care of the "missing" days.
+                if (gregorianCutoverYearJulian <= gregorianCutoverYear) {
+                    // We need to find out where we are. The cutover
+                    // gap could even be more than one year.  (One
+                    // year difference in ~48667 years.)
+                    fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
+                    if (fixedDate >= gregorianCutoverDate) {
+                        fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
+                    }
+                }
+                int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+                cutoverGap = dayOfYear - realDayOfYear;
+                dayOfYear = realDayOfYear;
+                relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
+            }
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // the Gregorian cutover year, we need to take care of
+                // it.  Usually the previous day of January 1 is
+                // December 31, which is not always true in
+                // GregorianCalendar.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1  = fixedDateJan1 - 365;
+                if (normalizedYear > (cutoverYear + 1)) {
+                    if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else if (normalizedYear <= gregorianCutoverYearJulian) {
+                    if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    //int prevYear = normalizedYear - 1;
+                    int prevYear = getCalendarDate(fixedDec31).getNormalizedYear();
+                    if (prevYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                        if (calForJan1 == jcal) {
+                            prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                               BaseCalendar.JANUARY,
+                                                               1,
+                                                               null);
+                        } else {
+                            prevJan1 = gregorianCutoverDate;
+                            calForJan1 = gcal;
+                        }
+                    } else if (prevYear <= gregorianCutoverYearJulian) {
+                        calForJan1 = getJulianCalendarSystem();
+                        prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    }
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (normalizedYear > gregorianCutoverYear ||
+                    normalizedYear < (gregorianCutoverYearJulian - 1)) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (cdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                  getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    int nextYear = normalizedYear + 1;
+                    if (nextYear == (gregorianCutoverYearJulian + 1) &&
+                        nextYear < gregorianCutoverYear) {
+                        // In case the gap is more than one year.
+                        nextYear = gregorianCutoverYear;
+                    }
+                    if (nextYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                    }
+
+                    long nextJan1;
+                    if (nextYear > gregorianCutoverYear
+                        || gregorianCutoverYearJulian == gregorianCutoverYear
+                        || nextYear == gregorianCutoverYearJulian) {
+                        nextJan1 = calForJan1.getFixedDate(nextYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    } else {
+                        nextJan1 = gregorianCutoverDate;
+                        calForJan1 = gcal;
+                    }
+
+                    long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                              getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `gcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = Gregorian.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @throws    IllegalArgumentException if any calendar fields are invalid.
+     */
+    @Override
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        // The year defaults to the epoch start. We don't check
+        // fieldMask for YEAR because YEAR is a mandatory field to
+        // determine the date.
+        int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
+
+        int era = internalGetEra();
+        if (era == BCE) {
+            year = 1 - year;
+        } else if (era != CE) {
+            // Even in lenient mode we disallow ERA values other than CE & BCE.
+            // (The same normalization rule as add()/roll() could be
+            // applied here in lenient mode. But this checking is kept
+            // unchanged for compatibility as of 1.5.)
+            throw new IllegalArgumentException("Invalid era");
+        }
+
+        // If year is 0 or negative, we need to set the ERA value later.
+        if (year <= 0 && !isSet(ERA)) {
+            fieldMask |= ERA_MASK;
+            setFieldsComputed(ERA_MASK);
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        calculateFixedDate: {
+            long gfd, jfd;
+            if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+                if (gfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+            } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                }
+                gfd = jfd;
+            } else {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+            }
+
+            // Now we have to determine which calendar date it is.
+
+            // If the date is relative from the beginning of the year
+            // in the Julian calendar, then use jfd;
+            if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                } else if (year == gregorianCutoverYear) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+            }
+
+            if (gfd >= gregorianCutoverDate) {
+                if (jfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                } else {
+                    // The date is in an "overlapping" period. No way
+                    // to disambiguate it. Determine it using the
+                    // previous date calculation.
+                    if (calsys == gcal || calsys == null) {
+                        fixedDate = gfd;
+                    } else {
+                        fixedDate = jfd;
+                    }
+                }
+            } else {
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                } else {
+                    // The date is in a "missing" period.
+                    if (!isLenient()) {
+                        throw new IllegalArgumentException("the specified date doesn't exist");
+                    }
+                    // Take the Julian date for compatibility, which
+                    // will produce a Gregorian date.
+                    fixedDate = jfd;
+                }
+            }
+        }
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        // BEGIN Android-changed: time zone related calculation via helper methods.
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+
+        millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
+        // END Android-changed: time zone related calculation via helper methods.
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    String s = originalFields[field] + " -> " + internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + ": " + s);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    // BEGIN Android-added: helper methods for time zone related calculation.
+    /**
+     * Calculates the time in milliseconds that this calendar represents using the UTC time,
+     * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
+     * of what fields were explicitly set on the calendar.
+     *
+     * <p>A time is represented as the number of milliseconds since
+     * <i>1st January 1970 00:00:00.000 UTC</i>.
+     *
+     * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time},
+     * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as
+     * used in {@link SimpleTimeZone}. Specifically:
+     *
+     * <dl>
+     * <dt><b>UTC time</b></dt>
+     * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time,
+     * standard time and wall time are all identical within the UTC time zone.</dd>
+     * <dt><b>standard time</b></dt>
+     * <dd>This is the local time within the time zone and is not affected by DST.</dd>
+     * <dt><b>wall time</b></dt>
+     * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone
+     * supports DST then it will be the same as <b>standard time</b> when outside DST and it will
+     * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar
+     * represent.</dd>
+     * </dl>
+     *
+     * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented
+     * a standard time in the {@code UTC} time zone. It is the value that would be returned by
+     * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If
+     * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of
+     * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a
+     * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to
+     * 0.
+     *
+     * <p>To adjust from a UTC time in millis to the standard time in millis we must
+     * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert
+     * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to
+     * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00.
+     *
+     * <p>As the zone offset can depend on the time and we cannot calculate the time properly until
+     * we know the time there is a bit of a catch-22. So, what this does is use the
+     * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then
+     * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They
+     * are then used to make the final wall time calculation.
+     *
+     * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See
+     * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information.
+     *
+     * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and
+     * {@link #DST_OFFSET_MASK}
+     * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT.
+     * @param zone the actual time zone.
+     * @return the UTC time in millis after adjusting for zone and DST offset.
+     */
+    private long adjustForZoneAndDaylightSavingsTime(
+            int tzMask, long utcTimeInMillis, TimeZone zone) {
+
+        // The following don't actually need to be initialized because they are always set before
+        // they are used but the compiler cannot detect that.
+        int zoneOffset = 0;
+        int dstOffset = 0;
+
+        // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information
+        // from the TimeZone.
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (zoneOffsets == null) {
+                zoneOffsets = new int[2];
+            }
+            int gmtOffset = isFieldSet(tzMask, ZONE_OFFSET) ?
+                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
+
+            // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure
+            // and not used in the final calculation as the offset used here may not be the same as
+            // the actual offset the time zone requires be used for this time. This is to handle
+            // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00
+            // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30
+            // for dates before the change over.
+            long standardTimeInZone = utcTimeInMillis - gmtOffset;
+
+            // Retrieve the correct zone and DST offsets from the time zone.
+            if (zone instanceof ZoneInfo) {
+                // Android-changed: libcore ZoneInfo uses different method to get offsets.
+                ZoneInfo zoneInfo = (ZoneInfo) zone;
+                zoneInfo.getOffsetsByUtcTime(standardTimeInZone, zoneOffsets);
+            } else {
+                zone.getOffsets(standardTimeInZone, zoneOffsets);
+            }
+            zoneOffset = zoneOffsets[0];
+            dstOffset = zoneOffsets[1];
+
+            // If necessary adjust the DST offset to handle an invalid wall clock sensibly.
+            dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset);
+        }
+
+        // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the
+        // fields, potentially overriding information from the TimeZone.
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffset = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                dstOffset = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        long standardTimeInZone = utcTimeInMillis - zoneOffset;
+        return standardTimeInZone - dstOffset;
+    }
+
+    /**
+     * If the supplied millis is in daylight savings time (DST) and is the result of an invalid
+     * wall clock then adjust the DST offset to ensure sensible behavior.
+     *
+     * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour)
+     * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks
+     * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of
+     * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to
+     * 03:00. The following table shows the relationship between the time in millis, the standard
+     * time and the wall time at the point of transitioning into DST. As can be seen there is no
+     * 02:00 in the wall time.
+     *
+     * <pre>
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 .....
+     * Wall Time      - ...... 01:00 ..... 03:00 ..... 04:00 .....
+     *                                       ^
+     *                                 02:00 missing
+     * </pre>
+     *
+     * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so
+     * that it is in that invalid period then this code attempts to do something sensible. It
+     * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both
+     * the input calendar fields perspective and from the time in millis perspective. Of course the
+     * result of that is that when the time is formatted in that time zone that the time is
+     * actually 03:MM:SS.SSS.
+     *
+     * <pre>
+     * Wall Time      - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h ..... <b> x+2h .....</b>  x+2h .....  x+3h .....
+     * </pre>
+     *
+     * <p>The way that works is as follows. First the standard time is calculated and the DST
+     * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in
+     * DST an hour earlier (or however long the DST offset is) then it must be in that invalid
+     * period, in which case set the DST offset to 0. That is then subtracted from the time in
+     * millis to produce the correct result. The following diagram illustrates the process.
+     *
+     * <pre>
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h .....  x+4h .....
+     * DST Offset     - ......    0h .....    1h .....    1h .....    1h .....
+     * Adjusted DST   - ......    0h .....    <b>0h</b> .....    1h .....    1h .....
+     * Adjusted Time  - ......  x+1h .....  x+2h .....  <b>x+2h</b> .....  <b>x+3h</b> .....
+     * </pre>
+     *
+     * @return the adjusted DST offset.
+     */
+    private int adjustDstOffsetForInvalidWallClock(
+            long standardTimeInZone, TimeZone zone, int dstOffset) {
+
+        if (dstOffset != 0) {
+            // If applying the DST offset produces a time that is outside DST then it must be
+            // an invalid wall clock so clear the DST offset to avoid that happening.
+            if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) {
+                dstOffset = 0;
+            }
+        }
+        return dstOffset;
+    }
+    // END Android-added: helper methods for time zone related calculation.
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param cal the CalendarSystem to be used for the date calculation
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
+        int month = JANUARY;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        }
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = cal.getFixedDate(year, month + 1, 1,
+                                          cal == gcal ? gdate : null);
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the first day of the month. Just add the
+                // offset if DAY_OF_MONTH is set. If the isSet call
+                // returns false, that means DAY_OF_MONTH has been
+                // selected just because of the selected
+                // combination. We don't need to add any since the
+                // default value is the 1st.
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-1, add
+                    // DAY_OF_MONTH, then subtract 1.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate--;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                  getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                            dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                            dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            if (year == gregorianCutoverYear && cal == gcal
+                && fixedDate < gregorianCutoverDate
+                && gregorianCutoverYear != gregorianCutoverYearJulian) {
+                // January 1 of the year doesn't exist.  Use
+                // gregorianCutoverDate as the first day of the
+                // year.
+                fixedDate = gregorianCutoverDate;
+            }
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                              getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+
+        return fixedDate;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private GregorianCalendar getNormalizedCalendar() {
+        GregorianCalendar gc;
+        if (isFullyNormalized()) {
+            gc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            gc = (GregorianCalendar) this.clone();
+            gc.setLenient(true);
+            gc.complete();
+        }
+        return gc;
+    }
+
+    /**
+     * Returns the Julian calendar system instance (singleton). 'jcal'
+     * and 'jeras' are set upon the return.
+     */
+    private static synchronized BaseCalendar getJulianCalendarSystem() {
+        if (jcal == null) {
+            jcal = (JulianCalendar) CalendarSystem.forName("julian");
+            jeras = jcal.getEras();
+        }
+        return jcal;
+    }
+
+    /**
+     * Returns the calendar system for dates before the cutover date
+     * in the cutover year. If the cutover date is January 1, the
+     * method returns Gregorian. Otherwise, Julian.
+     */
+    private BaseCalendar getCutoverCalendarSystem() {
+        if (gregorianCutoverYearJulian < gregorianCutoverYear) {
+            return gcal;
+        }
+        return getJulianCalendarSystem();
+    }
+
+    /**
+     * Determines if the specified year (normalized) is the Gregorian
+     * cutover year. This object must have been normalized.
+     */
+    private boolean isCutoverYear(int normalizedYear) {
+        int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+        return normalizedYear == cutoverYear;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        if (gregorianCutoverYear != gregorianCutoverYearJulian) {
+            if (fixedDate >= gregorianCutoverDate) {
+                // Dates before the cutover date don't exist
+                // in the same (Gregorian) year. So, no
+                // January 1 exists in the year. Use the
+                // cutover date as the first day of the year.
+                return gregorianCutoverDate;
+            }
+        }
+        // January 1 of the normalized year should exist.
+        BaseCalendar juliancal = getJulianCalendarSystem();
+        return juliancal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        BaseCalendar.Date gCutover = getGregorianCutoverDate();
+        if (gCutover.getMonth() == BaseCalendar.JANUARY
+            && gCutover.getDayOfMonth() == 1) {
+            // The cutover happened on January 1.
+            return fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        long fixedDateMonth1;
+        // The cutover happened sometime during the year.
+        if (date.getMonth() == gCutover.getMonth()) {
+            // The cutover happened in the month.
+            BaseCalendar.Date jLastDate = getLastJulianDate();
+            if (gregorianCutoverYear == gregorianCutoverYearJulian
+                && gCutover.getMonth() == jLastDate.getMonth()) {
+                // The "gap" fits in the same month.
+                fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
+                                                    date.getMonth(),
+                                                    1,
+                                                    null);
+            } else {
+                // Use the cutover date as the first day of the month.
+                fixedDateMonth1 = gregorianCutoverDate;
+            }
+        } else {
+            // The cutover happened before the month.
+            fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        return fixedDateMonth1;
+    }
+
+    /**
+     * Returns a CalendarDate produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private BaseCalendar.Date getCalendarDate(long fd) {
+        BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+        BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the Gregorian cutover date as a BaseCalendar.Date. The
+     * date is a Gregorian date.
+     */
+    private BaseCalendar.Date getGregorianCutoverDate() {
+        return getCalendarDate(gregorianCutoverDate);
+    }
+
+    /**
+     * Returns the day before the Gregorian cutover date as a
+     * BaseCalendar.Date. The date is a Julian date.
+     */
+    private BaseCalendar.Date getLastJulianDate() {
+        return getCalendarDate(gregorianCutoverDate - 1);
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * year. The year number must be normalized.
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month, int year) {
+        return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return monthLength(month, year);
+    }
+
+    private int actualMonthLength() {
+        int year = cdate.getNormalizedYear();
+        if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
+            return calsys.getMonthLength(cdate);
+        }
+        BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
+        long fd = calsys.getFixedDate(date);
+        long month1 = getFixedDateMonth1(date, fd);
+        long next1 = month1 + calsys.getMonthLength(date);
+        if (next1 < gregorianCutoverDate) {
+            return (int)(next1 - month1);
+        }
+        if (cdate != gdate) {
+            date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        }
+        gcal.getCalendarDateFromFixedDate(date, next1);
+        next1 = getFixedDateMonth1(date, next1);
+        return (int)(next1 - month1);
+    }
+
+    /**
+     * Returns the length (in days) of the specified year. The year
+     * must be normalized.
+     */
+    private int yearLength(int year) {
+        return isLeapYear(year) ? 366 : 365;
+    }
+
+    /**
+     * Returns the length (in days) of the year provided by
+     * internalGet(YEAR).
+     */
+    private int yearLength() {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return yearLength(year);
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth() {
+        int year = internalGet(YEAR);
+        int monthLen;
+        if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
+            monthLen = monthLength(internalGet(MONTH));
+        } else {
+            GregorianCalendar gc = getNormalizedCalendar();
+            monthLen = gc.getActualMaximum(DAY_OF_MONTH);
+        }
+        int dom = internalGet(DAY_OF_MONTH);
+        if (dom > monthLen) {
+            set(DAY_OF_MONTH, monthLen);
+        }
+    }
+
+    /**
+     * Returns the fixed date value of this object. The time value and
+     * calendar fields must be in synch.
+     */
+    private long getCurrentFixedDate() {
+        return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is CE, but a zero (unset) ERA is BCE.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : CE;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (gdate == null) {
+            gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+        setGregorianChange(gregorianCutover);
+    }
+
+    /**
+     * Converts this object to a {@code ZonedDateTime} that represents
+     * the same point on the time-line as this {@code GregorianCalendar}.
+     * <p>
+     * Since this object supports a Julian-Gregorian cutover date and
+     * {@code ZonedDateTime} does not, it is possible that the resulting year,
+     * month and day will have different values.  The result will represent the
+     * correct date in the ISO calendar system, which will also be the same value
+     * for Modified Julian Days.
+     *
+     * @return a zoned date-time representing the same point on the time-line
+     *  as this gregorian calendar
+     * @since 1.8
+     */
+    public ZonedDateTime toZonedDateTime() {
+        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()),
+                                       getTimeZone().toZoneId());
+    }
+
+    /**
+     * Obtains an instance of {@code GregorianCalendar} with the default locale
+     * from a {@code ZonedDateTime} object.
+     * <p>
+     * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover
+     * date and uses ISO calendar system, the return GregorianCalendar is a pure
+     * Gregorian calendar and uses ISO 8601 standard for week definitions,
+     * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek()
+     * FirstDayOfWeek} and {@code 4} as the value of the
+     * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}.
+     * <p>
+     * {@code ZoneDateTime} can store points on the time-line further in the
+     * future and further in the past than {@code GregorianCalendar}. In this
+     * scenario, this method will throw an {@code IllegalArgumentException}
+     * exception.
+     *
+     * @param zdt  the zoned date-time object to convert
+     * @return  the gregorian calendar representing the same point on the
+     *  time-line as the zoned date-time provided
+     * @throws    NullPointerException if {@code zdt} is null
+     * @throws    IllegalArgumentException if the zoned date-time is too
+     * large to represent as a {@code GregorianCalendar}
+     * @since 1.8
+     */
+    public static GregorianCalendar from(ZonedDateTime zdt) {
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone()));
+        cal.setGregorianChange(new Date(Long.MIN_VALUE));
+        cal.setFirstDayOfWeek(MONDAY);
+        cal.setMinimalDaysInFirstWeek(4);
+        try {
+            cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000),
+                                              zdt.get(ChronoField.MILLI_OF_SECOND)));
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return cal;
+    }
+}
diff --git a/android-35/java/util/HashMap.java b/android-35/java/util/HashMap.java
new file mode 100644
index 0000000..b1996b5
--- /dev/null
+++ b/android-35/java/util/HashMap.java
@@ -0,0 +1,2585 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify itA
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Hash table based implementation of the {@code Map} interface.  This
+ * implementation provides all of the optional map operations, and permits
+ * {@code null} values and the {@code null} key.  (The {@code HashMap}
+ * class is roughly equivalent to {@code Hashtable}, except that it is
+ * unsynchronized and permits nulls.)  This class makes no guarantees as to
+ * the order of the map; in particular, it does not guarantee that the order
+ * will remain constant over time.
+ *
+ * <p>This implementation provides constant-time performance for the basic
+ * operations ({@code get} and {@code put}), assuming the hash function
+ * disperses the elements properly among the buckets.  Iteration over
+ * collection views requires time proportional to the "capacity" of the
+ * {@code HashMap} instance (the number of buckets) plus its size (the number
+ * of key-value mappings).  Thus, it's very important not to set the initial
+ * capacity too high (or the load factor too low) if iteration performance is
+ * important.
+ *
+ * <p>An instance of {@code HashMap} has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of buckets in the hash table, and the initial
+ * capacity is simply the capacity at the time the hash table is created.  The
+ * <i>load factor</i> is a measure of how full the hash table is allowed to
+ * get before its capacity is automatically increased.  When the number of
+ * entries in the hash table exceeds the product of the load factor and the
+ * current capacity, the hash table is <i>rehashed</i> (that is, internal data
+ * structures are rebuilt) so that the hash table has approximately twice the
+ * number of buckets.
+ *
+ * <p>As a general rule, the default load factor (.75) offers a good
+ * tradeoff between time and space costs.  Higher values decrease the
+ * space overhead but increase the lookup cost (reflected in most of
+ * the operations of the {@code HashMap} class, including
+ * {@code get} and {@code put}).  The expected number of entries in
+ * the map and its load factor should be taken into account when
+ * setting its initial capacity, so as to minimize the number of
+ * rehash operations.  If the initial capacity is greater than the
+ * maximum number of entries divided by the load factor, no rehash
+ * operations will ever occur.
+ *
+ * <p>If many mappings are to be stored in a {@code HashMap}
+ * instance, creating it with a sufficiently large capacity will allow
+ * the mappings to be stored more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table.  Note that using
+ * many keys with the same {@code hashCode()} is a sure way to slow
+ * down performance of any hash table. To ameliorate impact, when keys
+ * are {@link Comparable}, this class may use comparison order among
+ * keys to help break ties.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash map concurrently, and at least one of
+ * the threads modifies the map structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new HashMap(...));</pre>
+ *
+ * <p>The iterators returned by all of this class's "collection view methods"
+ * are <i>fail-fast</i>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the
+ * future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Doug Lea
+ * @author  Josh Bloch
+ * @author  Arthur van Hoff
+ * @author  Neal Gafter
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.2
+ */
+public class HashMap<K,V> extends AbstractMap<K,V>
+    implements Map<K,V>, Cloneable, Serializable {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /*
+     * Implementation notes.
+     *
+     * This map usually acts as a binned (bucketed) hash table, but
+     * when bins get too large, they are transformed into bins of
+     * TreeNodes, each structured similarly to those in
+     * java.util.TreeMap. Most methods try to use normal bins, but
+     * relay to TreeNode methods when applicable (simply by checking
+     * instanceof a node).  Bins of TreeNodes may be traversed and
+     * used like any others, but additionally support faster lookup
+     * when overpopulated. However, since the vast majority of bins in
+     * normal use are not overpopulated, checking for existence of
+     * tree bins may be delayed in the course of table methods.
+     *
+     * Tree bins (i.e., bins whose elements are all TreeNodes) are
+     * ordered primarily by hashCode, but in the case of ties, if two
+     * elements are of the same "class C implements Comparable<C>",
+     * type then their compareTo method is used for ordering. (We
+     * conservatively check generic types via reflection to validate
+     * this -- see method comparableClassFor).  The added complexity
+     * of tree bins is worthwhile in providing worst-case O(log n)
+     * operations when keys either have distinct hashes or are
+     * orderable, Thus, performance degrades gracefully under
+     * accidental or malicious usages in which hashCode() methods
+     * return values that are poorly distributed, as well as those in
+     * which many keys share a hashCode, so long as they are also
+     * Comparable. (If neither of these apply, we may waste about a
+     * factor of two in time and space compared to taking no
+     * precautions. But the only known cases stem from poor user
+     * programming practices that are already so slow that this makes
+     * little difference.)
+     *
+     * Because TreeNodes are about twice the size of regular nodes, we
+     * use them only when bins contain enough nodes to warrant use
+     * (see TREEIFY_THRESHOLD). And when they become too small (due to
+     * removal or resizing) they are converted back to plain bins.  In
+     * usages with well-distributed user hashCodes, tree bins are
+     * rarely used.  Ideally, under random hashCodes, the frequency of
+     * nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average for the default resizing
+     * threshold of 0.75, although with a large variance because of
+     * resizing granularity. Ignoring variance, the expected
+     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
+     * factorial(k)). The first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * The root of a tree bin is normally its first node.  However,
+     * sometimes (currently only upon Iterator.remove), the root might
+     * be elsewhere, but can be recovered following parent links
+     * (method TreeNode.root()).
+     *
+     * All applicable internal methods accept a hash code as an
+     * argument (as normally supplied from a public method), allowing
+     * them to call each other without recomputing user hashCodes.
+     * Most internal methods also accept a "tab" argument, that is
+     * normally the current table, but may be a new or old one when
+     * resizing or converting.
+     *
+     * When bin lists are treeified, split, or untreeified, we keep
+     * them in the same relative access/traversal order (i.e., field
+     * Node.next) to better preserve locality, and to slightly
+     * simplify handling of splits and traversals that invoke
+     * iterator.remove. When using comparators on insertion, to keep a
+     * total ordering (or as close as is required here) across
+     * rebalancings, we compare classes and identityHashCodes as
+     * tie-breakers.
+     *
+     * The use and transitions among plain vs tree modes is
+     * complicated by the existence of subclass LinkedHashMap. See
+     * below for hook methods defined to be invoked upon insertion,
+     * removal and access that allow LinkedHashMap internals to
+     * otherwise remain independent of these mechanics. (This also
+     * requires that a map instance be passed to some utility methods
+     * that may create new nodes.)
+     *
+     * The concurrent-programming-like SSA-based coding style helps
+     * avoid aliasing errors amid all of the twisty pointer operations.
+     */
+
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2 and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
+     * between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Basic hash bin node, used for most entries.  (See below for
+     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        V value;
+        Node<K,V> next;
+
+        Node(int hash, K key, V value, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        public final K getKey()        { return key; }
+        public final V getValue()      { return value; }
+        public final String toString() { return key + "=" + value; }
+
+        public final int hashCode() {
+            return Objects.hashCode(key) ^ Objects.hashCode(value);
+        }
+
+        public final V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public final boolean equals(Object o) {
+            if (o == this)
+                return true;
+
+            return o instanceof Map.Entry<?, ?> e
+                    && Objects.equals(key, e.getKey())
+                    && Objects.equals(value, e.getValue());
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Computes key.hashCode() and spreads (XORs) higher bits of hash
+     * to lower.  Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int hash(Object key) {
+        int h;
+        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (Type t : ts) {
+                    if ((t instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType) t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /**
+     * Returns a power of two size for the given target capacity.
+     */
+    static final int tableSizeFor(int cap) {
+        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The table, initialized on first use, and resized as
+     * necessary. When allocated, length is always a power of two.
+     * (We also tolerate length zero in some operations to allow
+     * bootstrapping mechanics that are currently not needed.)
+     */
+    transient Node<K,V>[] table;
+
+    /**
+     * Holds cached entrySet(). Note that AbstractMap fields are used
+     * for keySet() and values().
+     */
+    transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * The number of key-value mappings contained in this map.
+     */
+    transient int size;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient int modCount;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     *
+     * @serial
+     */
+    // (The javadoc description is true upon serialization.
+    // Additionally, if the table array has not been allocated, this
+    // field holds the initial array capacity, or zero signifying
+    // DEFAULT_INITIAL_CAPACITY.)
+    int threshold;
+
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Constructs an empty {@code HashMap} with the specified initial
+     * capacity and load factor.
+     *
+     * @apiNote
+     * To create a {@code HashMap} with an initial capacity that accommodates
+     * an expected number of mappings, use {@link #newHashMap(int) newHashMap}.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public HashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+        this.loadFactor = loadFactor;
+        this.threshold = tableSizeFor(initialCapacity);
+    }
+
+    /**
+     * Constructs an empty {@code HashMap} with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @apiNote
+     * To create a {@code HashMap} with an initial capacity that accommodates
+     * an expected number of mappings, use {@link #newHashMap(int) newHashMap}.
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public HashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty {@code HashMap} with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public HashMap() {
+        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
+    }
+
+    /**
+     * Constructs a new {@code HashMap} with the same mappings as the
+     * specified {@code Map}.  The {@code HashMap} is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified {@code Map}.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     */
+    public HashMap(Map<? extends K, ? extends V> m) {
+        this.loadFactor = DEFAULT_LOAD_FACTOR;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Implements Map.putAll and Map constructor.
+     *
+     * @param m the map
+     * @param evict false when initially constructing this map, else
+     * true (relayed to method afterNodeInsertion).
+     */
+    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
+        int s = m.size();
+        if (s > 0) {
+            if (table == null) { // pre-size
+                double dt = Math.ceil(s / (double)loadFactor);
+                int t = ((dt < (double)MAXIMUM_CAPACITY) ?
+                         (int)dt : MAXIMUM_CAPACITY);
+                if (t > threshold)
+                    threshold = tableSizeFor(t);
+            } else {
+                // Because of linked-list bucket constraints, we cannot
+                // expand all at once, but can reduce total resize
+                // effort by repeated doubling now vs later
+                while (s > threshold && table.length < MAXIMUM_CAPACITY)
+                    resize();
+            }
+
+            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                putVal(hash(key), key, value, false, evict);
+            }
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        return (e = getNode(key)) == null ? null : e.value;
+    }
+
+    /**
+     * Implements Map.get and related methods.
+     *
+     * @param key the key
+     * @return the node, or null if none
+     */
+    final Node<K,V> getNode(Object key) {
+        Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (first = tab[(n - 1) & (hash = hash(key))]) != null) {
+            if (first.hash == hash && // always check first node
+                ((k = first.key) == key || (key != null && key.equals(k))))
+                return first;
+            if ((e = first.next) != null) {
+                if (first instanceof TreeNode)
+                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(Object key) {
+        return getNode(key) != null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     */
+    public V put(K key, V value) {
+        return putVal(hash(key), key, value, false, true);
+    }
+
+    /**
+     * Implements Map.put and related methods.
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to put
+     * @param onlyIfAbsent if true, don't change existing value
+     * @param evict if false, the table is in creation mode.
+     * @return previous value, or null if none
+     */
+    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
+                   boolean evict) {
+        Node<K,V>[] tab; Node<K,V> p; int n, i;
+        if ((tab = table) == null || (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((p = tab[i = (n - 1) & hash]) == null)
+            tab[i] = newNode(hash, key, value, null);
+        else {
+            Node<K,V> e; K k;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                e = p;
+            else if (p instanceof TreeNode)
+                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
+            else {
+                for (int binCount = 0; ; ++binCount) {
+                    if ((e = p.next) == null) {
+                        p.next = newNode(hash, key, value, null);
+                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
+                            treeifyBin(tab, hash);
+                        break;
+                    }
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        break;
+                    p = e;
+                }
+            }
+            if (e != null) { // existing mapping for key
+                V oldValue = e.value;
+                if (!onlyIfAbsent || oldValue == null)
+                    e.value = value;
+                afterNodeAccess(e);
+                return oldValue;
+            }
+        }
+        ++modCount;
+        if (++size > threshold)
+            resize();
+        afterNodeInsertion(evict);
+        return null;
+    }
+
+    /**
+     * Initializes or doubles table size.  If null, allocates in
+     * accord with initial capacity target held in field threshold.
+     * Otherwise, 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 in the new table.
+     *
+     * @return the table
+     */
+    final Node<K,V>[] resize() {
+        Node<K,V>[] oldTab = table;
+        int oldCap = (oldTab == null) ? 0 : oldTab.length;
+        int oldThr = threshold;
+        int newCap, newThr = 0;
+        if (oldCap > 0) {
+            if (oldCap >= MAXIMUM_CAPACITY) {
+                threshold = Integer.MAX_VALUE;
+                return oldTab;
+            }
+            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
+                     oldCap >= DEFAULT_INITIAL_CAPACITY)
+                newThr = oldThr << 1; // double threshold
+        }
+        else if (oldThr > 0) // initial capacity was placed in threshold
+            newCap = oldThr;
+        else {               // zero initial threshold signifies using defaults
+            newCap = DEFAULT_INITIAL_CAPACITY;
+            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
+        }
+        if (newThr == 0) {
+            float ft = (float)newCap * loadFactor;
+            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+                      (int)ft : Integer.MAX_VALUE);
+        }
+        threshold = newThr;
+        @SuppressWarnings({"rawtypes","unchecked"})
+        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+        table = newTab;
+        if (oldTab != null) {
+            for (int j = 0; j < oldCap; ++j) {
+                Node<K,V> e;
+                if ((e = oldTab[j]) != null) {
+                    oldTab[j] = null;
+                    if (e.next == null)
+                        newTab[e.hash & (newCap - 1)] = e;
+                    else if (e instanceof TreeNode)
+                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
+                    else { // preserve order
+                        Node<K,V> loHead = null, loTail = null;
+                        Node<K,V> hiHead = null, hiTail = null;
+                        Node<K,V> next;
+                        do {
+                            next = e.next;
+                            if ((e.hash & oldCap) == 0) {
+                                if (loTail == null)
+                                    loHead = e;
+                                else
+                                    loTail.next = e;
+                                loTail = e;
+                            }
+                            else {
+                                if (hiTail == null)
+                                    hiHead = e;
+                                else
+                                    hiTail.next = e;
+                                hiTail = e;
+                            }
+                        } while ((e = next) != null);
+                        if (loTail != null) {
+                            loTail.next = null;
+                            newTab[j] = loHead;
+                        }
+                        if (hiTail != null) {
+                            hiTail.next = null;
+                            newTab[j + oldCap] = hiHead;
+                        }
+                    }
+                }
+            }
+        }
+        return newTab;
+    }
+
+    /**
+     * Replaces all linked nodes in bin at index for given hash unless
+     * table is too small, in which case resizes instead.
+     */
+    final void treeifyBin(Node<K,V>[] tab, int hash) {
+        int n, index; Node<K,V> e;
+        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
+            resize();
+        else if ((e = tab[index = (n - 1) & hash]) != null) {
+            TreeNode<K,V> hd = null, tl = null;
+            do {
+                TreeNode<K,V> p = replacementTreeNode(e, null);
+                if (tl == null)
+                    hd = p;
+                else {
+                    p.prev = tl;
+                    tl.next = p;
+                }
+                tl = p;
+            } while ((e = e.next) != null);
+            if ((tab[index] = hd) != null)
+                hd.treeify(tab);
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        putMapEntries(m, true);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     */
+    public V remove(Object key) {
+        Node<K,V> e;
+        return (e = removeNode(hash(key), key, null, false, true)) == null ?
+            null : e.value;
+    }
+
+    /**
+     * Implements Map.remove and related methods.
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to match if matchValue, else ignored
+     * @param matchValue if true only remove if value is equal
+     * @param movable if false do not move other nodes while removing
+     * @return the node, or null if none
+     */
+    final Node<K,V> removeNode(int hash, Object key, Object value,
+                               boolean matchValue, boolean movable) {
+        Node<K,V>[] tab; Node<K,V> p; int n, index;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (p = tab[index = (n - 1) & hash]) != null) {
+            Node<K,V> node = null, e; K k; V v;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                node = p;
+            else if ((e = p.next) != null) {
+                if (p instanceof TreeNode)
+                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
+                else {
+                    do {
+                        if (e.hash == hash &&
+                            ((k = e.key) == key ||
+                             (key != null && key.equals(k)))) {
+                            node = e;
+                            break;
+                        }
+                        p = e;
+                    } while ((e = e.next) != null);
+                }
+            }
+            if (node != null && (!matchValue || (v = node.value) == value ||
+                                 (value != null && value.equals(v)))) {
+                if (node instanceof TreeNode)
+                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
+                else if (node == p)
+                    tab[index] = node.next;
+                else
+                    p.next = node.next;
+                ++modCount;
+                --size;
+                afterNodeRemoval(node);
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        Node<K,V>[] tab;
+        modCount++;
+        if ((tab = table) != null && size > 0) {
+            size = 0;
+            for (int i = 0; i < tab.length; ++i)
+                tab[i] = null;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        Node<K,V>[] tab; V v;
+        if ((tab = table) != null && size > 0) {
+            for (Node<K,V> e : tab) {
+                for (; e != null; e = e.next) {
+                    if ((v = e.value) == value ||
+                        (value != null && value.equals(v)))
+                        return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    /**
+     * Prepares the array for {@link Collection#toArray(Object[])} implementation.
+     * If supplied array is smaller than this map size, a new array is allocated.
+     * If supplied array is bigger than this map size, a null is written at size index.
+     *
+     * @param a an original array passed to {@code toArray()} method
+     * @param <T> type of array elements
+     * @return an array ready to be filled and returned from {@code toArray()} method.
+     */
+    @SuppressWarnings("unchecked")
+    final <T> T[] prepareArray(T[] a) {
+        int size = this.size;
+        if (a.length < size) {
+            return (T[]) java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), size);
+        }
+        if (a.length > size) {
+            a[size] = null;
+        }
+        return a;
+    }
+
+    /**
+     * Fills an array with this map keys and returns it. This method assumes
+     * that input array is big enough to fit all the keys. Use
+     * {@link #prepareArray(Object[])} to ensure this.
+     *
+     * @param a an array to fill
+     * @param <T> type of array elements
+     * @return supplied array
+     */
+    <T> T[] keysToArray(T[] a) {
+        Object[] r = a;
+        Node<K,V>[] tab;
+        int idx = 0;
+        if (size > 0 && (tab = table) != null) {
+            for (Node<K,V> e : tab) {
+                for (; e != null; e = e.next) {
+                    r[idx++] = e.key;
+                }
+            }
+        }
+        return a;
+    }
+
+    /**
+     * Fills an array with this map values and returns it. This method assumes
+     * that input array is big enough to fit all the values. Use
+     * {@link #prepareArray(Object[])} to ensure this.
+     *
+     * @param a an array to fill
+     * @param <T> type of array elements
+     * @return supplied array
+     */
+    <T> T[] valuesToArray(T[] a) {
+        Object[] r = a;
+        Node<K,V>[] tab;
+        int idx = 0;
+        if (size > 0 && (tab = table) != null) {
+            for (Node<K,V> e : tab) {
+                for (; e != null; e = e.next) {
+                    r[idx++] = e.value;
+                }
+            }
+        }
+        return a;
+    }
+
+    final class KeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<K> iterator()     { return new KeyIterator(); }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator() {
+            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+
+        public Object[] toArray() {
+            return keysToArray(new Object[size]);
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return keysToArray(prepareArray(a));
+        }
+
+        public final void forEach(Consumer<? super K> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.key);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    final class Values extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<V> iterator()     { return new ValueIterator(); }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+
+        public Object[] toArray() {
+            return valuesToArray(new Object[size]);
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return valuesToArray(prepareArray(a));
+        }
+
+        public final void forEach(Consumer<? super V> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.value);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
+    }
+
+    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> e))
+                return false;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry<?, ?> e) {
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // Overrides of JDK8 Map extension methods
+
+    @Override
+    public V getOrDefault(Object key, V defaultValue) {
+        Node<K,V> e;
+        return (e = getNode(key)) == null ? defaultValue : e.value;
+    }
+
+    @Override
+    public V putIfAbsent(K key, V value) {
+        return putVal(hash(key), key, value, true, true);
+    }
+
+    @Override
+    public boolean remove(Object key, Object value) {
+        return removeNode(hash(key), key, value, true, true) != null;
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        Node<K,V> e; V v;
+        if ((e = getNode(key)) != null &&
+            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
+            e.value = newValue;
+            afterNodeAccess(e);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        Node<K,V> e;
+        if ((e = getNode(key)) != null) {
+            V oldValue = e.value;
+            e.value = value;
+            afterNodeAccess(e);
+            return oldValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * mapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * mapping function modified this map
+     */
+    @Override
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (mappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+            V oldValue;
+            if (old != null && (oldValue = old.value) != null) {
+                afterNodeAccess(old);
+                return oldValue;
+            }
+        }
+        int mc = modCount;
+        V v = mappingFunction.apply(key);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
+        if (v == null) {
+            return null;
+        } else if (old != null) {
+            old.value = v;
+            afterNodeAccess(old);
+            return v;
+        }
+        else if (t != null)
+            t.putTreeVal(this, tab, hash, key, v);
+        else {
+            tab[i] = newNode(hash, key, v, first);
+            if (binCount >= TREEIFY_THRESHOLD - 1)
+                treeifyBin(tab, hash);
+        }
+        modCount = mc + 1;
+        ++size;
+        afterNodeInsertion(true);
+        return v;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> e; V oldValue;
+        if ((e = getNode(key)) != null &&
+            (oldValue = e.value) != null) {
+            int mc = modCount;
+            V v = remappingFunction.apply(key, oldValue);
+            if (mc != modCount) { throw new ConcurrentModificationException(); }
+            if (v != null) {
+                e.value = v;
+                afterNodeAccess(e);
+                return v;
+            }
+            else {
+                int hash = hash(key);
+                removeNode(hash, key, null, false, true);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        V oldValue = (old == null) ? null : old.value;
+        int mc = modCount;
+        V v = remappingFunction.apply(key, oldValue);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
+        if (old != null) {
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+        }
+        else if (v != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, v);
+            else {
+                tab[i] = newNode(hash, key, v, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            modCount = mc + 1;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return v;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (value == null || remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        if (old != null) {
+            V v;
+            if (old.value != null) {
+                int mc = modCount;
+                v = remappingFunction.apply(old.value, value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            } else {
+                v = value;
+            }
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+            return v;
+        } else {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, value);
+            else {
+                tab[i] = newNode(hash, key, value, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+            return value;
+        }
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Node<K,V>[] tab;
+        if (action == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (int i = 0; (i < tab.length && mc == modCount); ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                    action.accept(e.key, e.value);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Node<K,V>[] tab;
+        if (function == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (Node<K,V> e : tab) {
+                for (; e != null; e = e.next) {
+                    e.value = function.apply(e.key, e.value);
+                }
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Cloning and serialization
+
+    /**
+     * Returns a shallow copy of this {@code HashMap} instance: the keys and
+     * values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object clone() {
+        HashMap<K,V> result;
+        try {
+            result = (HashMap<K,V>)super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+        result.reinitialize();
+        result.putMapEntries(this, false);
+        return result;
+    }
+
+    // These methods are also used when serializing HashSets
+    final float loadFactor() { return loadFactor; }
+    final int capacity() {
+        return (table != null) ? table.length :
+            (threshold > 0) ? threshold :
+            DEFAULT_INITIAL_CAPACITY;
+    }
+
+    /**
+     * Saves this map to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws IOException if an I/O error occurs
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> (an int, the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping.  The key-value mappings are
+     *             emitted in no particular order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException {
+        int buckets = capacity();
+        // Write out the threshold, loadfactor, and any hidden stuff
+        s.defaultWriteObject();
+        s.writeInt(buckets);
+        s.writeInt(size);
+        internalWriteEntries(s);
+    }
+
+    /**
+     * Reconstitute the {@code HashMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // Read loadFactor (ignore threshold)
+        float lf = fields.get("loadFactor", 0.75f);
+        if (lf <= 0 || Float.isNaN(lf))
+            throw new InvalidObjectException("Illegal load factor: " + lf);
+
+        lf = Math.clamp(lf, 0.25f, 4.0f);
+        HashMap.UnsafeHolder.putLoadFactor(this, lf);
+
+        reinitialize();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        s.readInt();                // Read and ignore number of buckets
+        int mappings = s.readInt(); // Read number of mappings (size)
+
+        if (mappings < 0) {
+            throw new InvalidObjectException("Illegal mappings count: " + mappings);
+        } else if (mappings == 0) {
+            // use defaults
+        } else if (mappings > 0) {
+            double dc = Math.ceil(mappings / (double)lf);
+            int cap = ((dc < DEFAULT_INITIAL_CAPACITY) ?
+                       DEFAULT_INITIAL_CAPACITY :
+                       (dc >= MAXIMUM_CAPACITY) ?
+                       MAXIMUM_CAPACITY :
+                       tableSizeFor((int)dc));
+            float ft = (float)cap * lf;
+            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
+                         (int)ft : Integer.MAX_VALUE);
+            @SuppressWarnings({"rawtypes","unchecked"})
+            Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+            table = tab;
+
+            // Read the keys and values, and put the mappings in the HashMap
+            for (int i = 0; i < mappings; i++) {
+                @SuppressWarnings("unchecked")
+                    K key = (K) s.readObject();
+                @SuppressWarnings("unchecked")
+                    V value = (V) s.readObject();
+                putVal(hash(key), key, value, false, false);
+            }
+        }
+    }
+
+    // Support for resetting final field during deserializing
+    private static final class UnsafeHolder {
+        private UnsafeHolder() { throw new InternalError(); }
+        private static final jdk.internal.misc.Unsafe unsafe
+                = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final long LF_OFFSET
+                = unsafe.objectFieldOffset(HashMap.class, "loadFactor");
+        static void putLoadFactor(HashMap<?, ?> map, float lf) {
+            unsafe.putFloat(map, LF_OFFSET, lf);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // iterators
+
+    abstract class HashIterator {
+        Node<K,V> next;        // next entry to return
+        Node<K,V> current;     // current entry
+        int expectedModCount;  // for fast-fail
+        int index;             // current slot
+
+        HashIterator() {
+            expectedModCount = modCount;
+            Node<K,V>[] t = table;
+            current = next = null;
+            index = 0;
+            if (t != null && size > 0) { // advance to first entry
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final Node<K,V> nextNode() {
+            Node<K,V>[] t;
+            Node<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            if ((next = (current = e).next) == null && (t = table) != null) {
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            removeNode(p.hash, p.key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class KeyIterator extends HashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().key; }
+    }
+
+    final class ValueIterator extends HashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class EntryIterator extends HashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+    /* ------------------------------------------------------------ */
+    // spliterators
+
+    static class HashMapSpliterator<K,V> {
+        final HashMap<K,V> map;
+        Node<K,V> current;          // current node
+        int index;                  // current index, modified on advance/split
+        int fence;                  // one past last index
+        int est;                    // size estimate
+        int expectedModCount;       // for comodification checks
+
+        HashMapSpliterator(HashMap<K,V> m, int origin,
+                           int fence, int est,
+                           int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                HashMap<K,V> m = map;
+                est = m.size;
+                expectedModCount = m.modCount;
+                Node<K,V>[] tab = m.table;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.key);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        K k = current.key;
+                        current = current.next;
+                        action.accept(k);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.value);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        V v = current.value;
+                        current = current.next;
+                        action.accept(v);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Node<K,V> e = current;
+                        current = current.next;
+                        action.accept(e);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // LinkedHashMap support
+
+
+    /*
+     * The following package-protected methods are designed to be
+     * overridden by LinkedHashMap, but not by any other subclass.
+     * Nearly all other internal methods are also package-protected
+     * but are declared final, so can be used by LinkedHashMap, view
+     * classes, and HashSet.
+     */
+
+    // Create a regular (non-tree) node
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
+        return new Node<>(hash, key, value, next);
+    }
+
+    // For conversion from TreeNodes to plain nodes
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        return new Node<>(p.hash, p.key, p.value, next);
+    }
+
+    // Create a tree bin node
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        return new TreeNode<>(hash, key, value, next);
+    }
+
+    // For treeifyBin
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        return new TreeNode<>(p.hash, p.key, p.value, next);
+    }
+
+    /**
+     * Reset to initial default state.  Called by clone and readObject.
+     */
+    void reinitialize() {
+        table = null;
+        entrySet = null;
+        keySet = null;
+        values = null;
+        modCount = 0;
+        threshold = 0;
+        size = 0;
+    }
+
+    // Callbacks to allow LinkedHashMap post-actions
+    void afterNodeAccess(Node<K,V> p) { }
+    void afterNodeInsertion(boolean evict) { }
+    void afterNodeRemoval(Node<K,V> p) { }
+
+    // Called only from writeObject, to ensure compatible ordering.
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        Node<K,V>[] tab;
+        if (size > 0 && (tab = table) != null) {
+            for (Node<K,V> e : tab) {
+                for (; e != null; e = e.next) {
+                    s.writeObject(e.key);
+                    s.writeObject(e.value);
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Tree bins
+
+    /**
+     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
+     * extends Node) so can be used as extension of either regular or
+     * linked node.
+     */
+    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+        TreeNode(int hash, K key, V val, Node<K,V> next) {
+            super(hash, key, val, next);
+        }
+
+        /**
+         * Returns root of tree containing this node.
+         */
+        final TreeNode<K,V> root() {
+            for (TreeNode<K,V> r = this, p;;) {
+                if ((p = r.parent) == null)
+                    return r;
+                r = p;
+            }
+        }
+
+        /**
+         * Ensures that the given root is the first node of its bin.
+         */
+        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
+            int n;
+            if (root != null && tab != null && (n = tab.length) > 0) {
+                int index = (n - 1) & root.hash;
+                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
+                if (root != first) {
+                    Node<K,V> rn;
+                    tab[index] = root;
+                    TreeNode<K,V> rp = root.prev;
+                    if ((rn = root.next) != null)
+                        ((TreeNode<K,V>)rn).prev = rp;
+                    if (rp != null)
+                        rp.next = rn;
+                    if (first != null)
+                        first.prev = root;
+                    root.next = first;
+                    root.prev = null;
+                }
+                assert checkInvariants(root);
+            }
+        }
+
+        /**
+         * Finds the node starting at root p with the given hash and key.
+         * The kc argument caches comparableClassFor(key) upon first use
+         * comparing keys.
+         */
+        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
+            TreeNode<K,V> p = this;
+            do {
+                int ph, dir; K pk;
+                TreeNode<K,V> pl = p.left, pr = p.right, q;
+                if ((ph = p.hash) > h)
+                    p = pl;
+                else if (ph < h)
+                    p = pr;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if (pl == null)
+                    p = pr;
+                else if (pr == null)
+                    p = pl;
+                else if ((kc != null ||
+                          (kc = comparableClassFor(k)) != null) &&
+                         (dir = compareComparables(kc, k, pk)) != 0)
+                    p = (dir < 0) ? pl : pr;
+                else if ((q = pr.find(h, k, kc)) != null)
+                    return q;
+                else
+                    p = pl;
+            } while (p != null);
+            return null;
+        }
+
+        /**
+         * Calls find for root node.
+         */
+        final TreeNode<K,V> getTreeNode(int h, Object k) {
+            return ((parent != null) ? root() : this).find(h, k, null);
+        }
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Forms tree of the nodes linked from this node.
+         */
+        final void treeify(Node<K,V>[] tab) {
+            TreeNode<K,V> root = null;
+            for (TreeNode<K,V> x = this, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (root == null) {
+                    x.parent = null;
+                    x.red = false;
+                    root = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = root;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            root = balanceInsertion(root, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            moveRootToFront(tab, root);
+        }
+
+        /**
+         * Returns a list of non-TreeNodes replacing those linked from
+         * this node.
+         */
+        final Node<K,V> untreeify(HashMap<K,V> map) {
+            Node<K,V> hd = null, tl = null;
+            for (Node<K,V> q = this; q != null; q = q.next) {
+                Node<K,V> p = map.replacementNode(q, null);
+                if (tl == null)
+                    hd = p;
+                else
+                    tl.next = p;
+                tl = p;
+            }
+            return hd;
+        }
+
+        /**
+         * Tree version of putVal.
+         */
+        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
+                                       int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            TreeNode<K,V> root = (parent != null) ? root() : this;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.find(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.find(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    Node<K,V> xpn = xp.next;
+                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    xp.next = x;
+                    x.parent = x.prev = xp;
+                    if (xpn != null)
+                        ((TreeNode<K,V>)xpn).prev = x;
+                    moveRootToFront(tab, balanceInsertion(root, x));
+                    return null;
+                }
+            }
+        }
+
+        /**
+         * Removes the given node, that must be present before this call.
+         * This is messier than typical red-black deletion code because we
+         * cannot swap the contents of an interior node with a leaf
+         * successor that is pinned by "next" pointers that are accessible
+         * independently during traversal. So instead we swap the tree
+         * linkages. If the current tree appears to have too few nodes,
+         * the bin is converted back to a plain bin. (The test triggers
+         * somewhere between 2 and 6 nodes, depending on tree structure).
+         */
+        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
+                                  boolean movable) {
+            int n;
+            if (tab == null || (n = tab.length) == 0)
+                return;
+            int index = (n - 1) & hash;
+            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
+            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
+            if (pred == null)
+                tab[index] = first = succ;
+            else
+                pred.next = succ;
+            if (succ != null)
+                succ.prev = pred;
+            if (first == null)
+                return;
+            if (root.parent != null)
+                root = root.root();
+            if (root == null
+                || (movable
+                    && (root.right == null
+                        || (rl = root.left) == null
+                        || rl.left == null))) {
+                tab[index] = first.untreeify(map);  // too small
+                return;
+            }
+            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
+            if (pl != null && pr != null) {
+                TreeNode<K,V> s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                    s = sl;
+                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                TreeNode<K,V> sr = s.right;
+                TreeNode<K,V> pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                }
+                else {
+                    TreeNode<K,V> sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left)
+                            sp.left = p;
+                        else
+                            sp.right = p;
+                    }
+                    if ((s.right = pr) != null)
+                        pr.parent = s;
+                }
+                p.left = null;
+                if ((p.right = sr) != null)
+                    sr.parent = p;
+                if ((s.left = pl) != null)
+                    pl.parent = s;
+                if ((s.parent = pp) == null)
+                    root = s;
+                else if (p == pp.left)
+                    pp.left = s;
+                else
+                    pp.right = s;
+                if (sr != null)
+                    replacement = sr;
+                else
+                    replacement = p;
+            }
+            else if (pl != null)
+                replacement = pl;
+            else if (pr != null)
+                replacement = pr;
+            else
+                replacement = p;
+            if (replacement != p) {
+                TreeNode<K,V> pp = replacement.parent = p.parent;
+                if (pp == null)
+                    (root = replacement).red = false;
+                else if (p == pp.left)
+                    pp.left = replacement;
+                else
+                    pp.right = replacement;
+                p.left = p.right = p.parent = null;
+            }
+
+            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
+
+            if (replacement == p) {  // detach
+                TreeNode<K,V> pp = p.parent;
+                p.parent = null;
+                if (pp != null) {
+                    if (p == pp.left)
+                        pp.left = null;
+                    else if (p == pp.right)
+                        pp.right = null;
+                }
+            }
+            if (movable)
+                moveRootToFront(tab, r);
+        }
+
+        /**
+         * Splits nodes in a tree bin into lower and upper tree bins,
+         * or untreeifies if now too small. Called only from resize;
+         * see above discussion about split bits and indices.
+         *
+         * @param map the map
+         * @param tab the table for recording bin heads
+         * @param index the index of the table being split
+         * @param bit the bit of hash to split on
+         */
+        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
+            TreeNode<K,V> b = this;
+            // Relink into lo and hi lists, preserving order
+            TreeNode<K,V> loHead = null, loTail = null;
+            TreeNode<K,V> hiHead = null, hiTail = null;
+            int lc = 0, hc = 0;
+            for (TreeNode<K,V> e = b, next; e != null; e = next) {
+                next = (TreeNode<K,V>)e.next;
+                e.next = null;
+                if ((e.hash & bit) == 0) {
+                    if ((e.prev = loTail) == null)
+                        loHead = e;
+                    else
+                        loTail.next = e;
+                    loTail = e;
+                    ++lc;
+                }
+                else {
+                    if ((e.prev = hiTail) == null)
+                        hiHead = e;
+                    else
+                        hiTail.next = e;
+                    hiTail = e;
+                    ++hc;
+                }
+            }
+
+            if (loHead != null) {
+                if (lc <= UNTREEIFY_THRESHOLD)
+                    tab[index] = loHead.untreeify(map);
+                else {
+                    tab[index] = loHead;
+                    if (hiHead != null) // (else is already treeified)
+                        loHead.treeify(tab);
+                }
+            }
+            if (hiHead != null) {
+                if (hc <= UNTREEIFY_THRESHOLD)
+                    tab[index + bit] = hiHead.untreeify(map);
+                else {
+                    tab[index + bit] = hiHead;
+                    if (loHead != null)
+                        hiHead.treeify(tab);
+                }
+            }
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;) {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Recursive invariant check
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+    }
+
+    /**
+     * Calculate initial capacity for HashMap based classes, from expected size and default load factor (0.75).
+     *
+     * @param numMappings the expected number of mappings
+     * @return initial capacity for HashMap based classes.
+     * @since 19
+     */
+    static int calculateHashMapCapacity(int numMappings) {
+        return (int) Math.ceil(numMappings / (double) DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Creates a new, empty HashMap suitable for the expected number of mappings.
+     * The returned map uses the default load factor of 0.75, and its initial capacity is
+     * generally large enough so that the expected number of mappings can be added
+     * without resizing the map.
+     *
+     * @param numMappings the expected number of mappings
+     * @param <K>         the type of keys maintained by the new map
+     * @param <V>         the type of mapped values
+     * @return the newly created map
+     * @throws IllegalArgumentException if numMappings is negative
+     * @since 19
+     */
+    public static <K, V> HashMap<K, V> newHashMap(int numMappings) {
+        if (numMappings < 0) {
+            throw new IllegalArgumentException("Negative number of mappings: " + numMappings);
+        }
+        return new HashMap<>(calculateHashMapCapacity(numMappings));
+    }
+
+}
diff --git a/android-35/java/util/HashSet.java b/android-35/java/util/HashSet.java
new file mode 100644
index 0000000..e59bf7b
--- /dev/null
+++ b/android-35/java/util/HashSet.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.InvalidObjectException;
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * This class implements the {@code Set} interface, backed by a hash table
+ * (actually a {@code HashMap} instance).  It makes no guarantees as to the
+ * iteration order of the set; in particular, it does not guarantee that the
+ * order will remain constant over time.  This class permits the {@code null}
+ * element.
+ *
+ * <p>This class offers constant time performance for the basic operations
+ * ({@code add}, {@code remove}, {@code contains} and {@code size}),
+ * assuming the hash function disperses the elements properly among the
+ * buckets.  Iterating over this set requires time proportional to the sum of
+ * the {@code HashSet} instance's size (the number of elements) plus the
+ * "capacity" of the backing {@code HashMap} instance (the number of
+ * buckets).  Thus, it's very important not to set the initial capacity too
+ * high (or the load factor too low) if iteration performance is important.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash set concurrently, and at least one of
+ * the threads modifies the set, it <i>must</i> be synchronized externally.
+ * This is typically accomplished by synchronizing on some object that
+ * naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set:<pre>
+ *   Set s = Collections.synchronizedSet(new HashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own {@code remove}
+ * method, the Iterator throws a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     TreeSet
+ * @see     HashMap
+ * @since   1.2
+ */
+
+public class HashSet<E>
+    extends AbstractSet<E>
+    implements Set<E>, Cloneable, java.io.Serializable
+{
+    @java.io.Serial
+    static final long serialVersionUID = -5024744406713321676L;
+
+    transient HashMap<E,Object> map;
+
+    // Dummy value to associate with an Object in the backing Map
+    static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a new, empty set; the backing {@code HashMap} instance has
+     * default initial capacity (16) and load factor (0.75).
+     */
+    public HashSet() {
+        map = new HashMap<>();
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection.  The {@code HashMap} is created with default load factor
+     * (0.75) and an initial capacity sufficient to contain the elements in
+     * the specified collection.
+     *
+     * @param c the collection whose elements are to be placed into this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public HashSet(Collection<? extends E> c) {
+        map = HashMap.newHashMap(Math.max(c.size(), 12));
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing {@code HashMap} instance has
+     * the specified initial capacity and the specified load factor.
+     *
+     * @apiNote
+     * To create a {@code HashSet} with an initial capacity that accommodates
+     * an expected number of elements, use {@link #newHashSet(int) newHashSet}.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    public HashSet(int initialCapacity, float loadFactor) {
+        map = new HashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing {@code HashMap} instance has
+     * the specified initial capacity and default load factor (0.75).
+     *
+     * @apiNote
+     * To create a {@code HashSet} with an initial capacity that accommodates
+     * an expected number of elements, use {@link #newHashSet(int) newHashSet}.
+     *
+     * @param      initialCapacity   the initial capacity of the hash table
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero
+     */
+    public HashSet(int initialCapacity) {
+        map = new HashMap<>(initialCapacity);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set.  (This package private
+     * constructor is only used by LinkedHashSet.) The backing
+     * HashMap instance is a LinkedHashMap with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @param      dummy             ignored (distinguishes this
+     *             constructor from other int, float constructor.)
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
+        map = new LinkedHashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements
+     * are returned in no particular order.
+     *
+     * @return an Iterator over the elements in this set
+     * @see ConcurrentModificationException
+     */
+    public Iterator<E> iterator() {
+        return map.keySet().iterator();
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return map.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * this set contains no element {@code e2} such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     * element
+     */
+    public boolean add(E e) {
+        return map.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code Objects.equals(o, e)},
+     * if this set contains such an element.  Returns {@code true} if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if the set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return map.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns a shallow copy of this {@code HashSet} instance: the elements
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        try {
+            HashSet<E> newSet = (HashSet<E>) super.clone();
+            newSet.map = (HashMap<E, Object>) map.clone();
+            return newSet;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Save the state of this {@code HashSet} instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData The capacity of the backing {@code HashMap} instance
+     *             (int), and its load factor (float) are emitted, followed by
+     *             the size of the set (the number of elements it contains)
+     *             (int), followed by all of its elements (each an Object) in
+     *             no particular order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out HashMap capacity and load factor
+        s.writeInt(map.capacity());
+        s.writeFloat(map.loadFactor());
+
+        // Write out size
+        s.writeInt(map.size());
+
+        // Write out all elements in the proper order.
+        for (E e : map.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the {@code HashSet} instance from a stream (that is,
+     * deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Consume and ignore stream fields (currently zero).
+        s.readFields();
+
+        // Read capacity and verify non-negative.
+        int capacity = s.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Illegal capacity: " +
+                                             capacity);
+        }
+
+        // Read load factor and verify positive and non NaN.
+        float loadFactor = s.readFloat();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        }
+        // Clamp load factor to range of 0.25...4.0.
+        loadFactor = Math.clamp(loadFactor, 0.25f, 4.0f);
+
+        // Read size and verify non-negative.
+        int size = s.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Illegal size: " + size);
+        }
+
+        // Set the capacity according to the size and load factor ensuring that
+        // the HashMap is at least 25% full but clamping to maximum capacity.
+        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
+                HashMap.MAXIMUM_CAPACITY);
+
+        // Constructing the backing map will lazily create an array when the first element is
+        // added, so check it before construction. Call HashMap.tableSizeFor to compute the
+        // actual allocation size. Check Map.Entry[].class since it's the nearest public type to
+        // what is actually created.
+        SharedSecrets.getJavaObjectInputStreamAccess()
+                     .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity));
+
+        // Create backing HashMap
+        map = (this instanceof LinkedHashSet ?
+               new LinkedHashMap<>(capacity, loadFactor) :
+               new HashMap<>(capacity, loadFactor));
+
+        // Read in all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                E e = (E) s.readObject();
+            map.put(e, PRESENT);
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#DISTINCT}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new HashMap.KeySpliterator<>(map, 0, -1, 0, 0);
+    }
+
+    @Override
+    public Object[] toArray() {
+        return map.keysToArray(new Object[map.size()]);
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return map.keysToArray(map.prepareArray(a));
+    }
+
+    /**
+     * Creates a new, empty HashSet suitable for the expected number of elements.
+     * The returned set uses the default load factor of 0.75, and its initial capacity is
+     * generally large enough so that the expected number of elements can be added
+     * without resizing the set.
+     *
+     * @param numElements    the expected number of elements
+     * @param <T>         the type of elements maintained by the new set
+     * @return the newly created set
+     * @throws IllegalArgumentException if numElements is negative
+     * @since 19
+     */
+    public static <T> HashSet<T> newHashSet(int numElements) {
+        if (numElements < 0) {
+            throw new IllegalArgumentException("Negative number of elements: " + numElements);
+        }
+        return new HashSet<>(HashMap.calculateHashMapCapacity(numElements));
+    }
+
+}
diff --git a/android-35/java/util/Hashtable.java b/android-35/java/util/Hashtable.java
new file mode 100644
index 0000000..2fcdc46
--- /dev/null
+++ b/android-35/java/util/Hashtable.java
@@ -0,0 +1,1553 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * This class implements a hash table, which maps keys to values. Any
+ * non-{@code null} object can be used as a key or as a value. <p>
+ *
+ * To successfully store and retrieve objects from a hashtable, the
+ * objects used as keys must implement the {@code hashCode}
+ * method and the {@code equals} method. <p>
+ *
+ * An instance of {@code Hashtable} has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
+ * <i>initial capacity</i> is simply the capacity at the time the hash table
+ * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
+ * collision", a single bucket stores multiple entries, which must be searched
+ * sequentially.  The <i>load factor</i> is a measure of how full the hash
+ * table is allowed to get before its capacity is automatically increased.
+ * The initial capacity and load factor parameters are merely hints to
+ * the implementation.  The exact details as to when and whether the rehash
+ * method is invoked are implementation-dependent.<p>
+ *
+ * Generally, the default load factor (.75) offers a good tradeoff between
+ * time and space costs.  Higher values decrease the space overhead but
+ * increase the time cost to look up an entry (which is reflected in most
+ * {@code Hashtable} operations, including {@code get} and {@code put}).<p>
+ *
+ * The initial capacity controls a tradeoff between wasted space and the
+ * need for {@code rehash} operations, which are time-consuming.
+ * No {@code rehash} operations will <i>ever</i> occur if the initial
+ * capacity is greater than the maximum number of entries the
+ * {@code Hashtable} will contain divided by its load factor.  However,
+ * setting the initial capacity too high can waste space.<p>
+ *
+ * If many entries are to be made into a {@code Hashtable},
+ * creating it with a sufficiently large capacity may allow the
+ * entries to be inserted more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table. <p>
+ *
+ * This example creates a hashtable of numbers. It uses the names of
+ * the numbers as keys:
+ * <pre>   {@code
+ *   Hashtable<String, Integer> numbers
+ *     = new Hashtable<String, Integer>();
+ *   numbers.put("one", 1);
+ *   numbers.put("two", 2);
+ *   numbers.put("three", 3);}</pre>
+ *
+ * <p>To retrieve a number, use the following code:
+ * <pre>   {@code
+ *   Integer n = numbers.get("two");
+ *   if (n != null) {
+ *     System.out.println("two = " + n);
+ *   }}</pre>
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
+ * after the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ * The Enumerations returned by Hashtable's {@link #keys keys} and
+ * {@link #elements elements} methods are <em>not</em> fail-fast; if the
+ * Hashtable is structurally modified at any time after the enumeration is
+ * created then the results of enumerating are undefined.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link Map} interface, making it a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ *
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Hashtable} is synchronized.  If a
+ * thread-safe implementation is not needed, it is recommended to use
+ * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
+ * highly-concurrent implementation is desired, then it is recommended
+ * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
+ * {@code Hashtable}.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Arthur van Hoff
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Object#equals(java.lang.Object)
+ * @see     Object#hashCode()
+ * @see     Hashtable#rehash()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @since 1.0
+ */
+public class Hashtable<K,V>
+    extends Dictionary<K,V>
+    implements Map<K,V>, Cloneable, java.io.Serializable {
+
+    /**
+     * The hash table data.
+     */
+    private transient HashtableEntry<?,?>[] table;
+
+    /**
+     * The total number of entries in the hash table.
+     */
+    private transient int count;
+
+    /**
+     * The table is rehashed when its size exceeds this threshold.  (The
+     * value of this field is (int)(capacity * loadFactor).)
+     *
+     * @serial
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hashtable.
+     *
+     * @serial
+     */
+    private float loadFactor;
+
+    /**
+     * The number of times this Hashtable has been structurally modified
+     * Structural modifications are those that change the number of entries in
+     * the Hashtable or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the Hashtable fail-fast.  (See ConcurrentModificationException).
+     */
+    private transient int modCount = 0;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    @java.io.Serial
+    private static final long serialVersionUID = 1421746759512286392L;
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hashtable.
+     * @param      loadFactor        the load factor of the hashtable.
+     * @throws     IllegalArgumentException  if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive.
+     */
+    public Hashtable(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
+
+        if (initialCapacity==0)
+            initialCapacity = 1;
+        this.loadFactor = loadFactor;
+        table = new HashtableEntry<?,?>[initialCapacity];
+        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial capacity
+     * and default load factor (0.75).
+     *
+     * @param     initialCapacity   the initial capacity of the hashtable.
+     * @throws    IllegalArgumentException if the initial capacity is less
+     *              than zero.
+     */
+    public Hashtable(int initialCapacity) {
+        this(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with a default initial capacity (11)
+     * and load factor (0.75).
+     */
+    public Hashtable() {
+        this(11, 0.75f);
+    }
+
+    /**
+     * Constructs a new hashtable with the same mappings as the given
+     * Map.  The hashtable is created with an initial capacity sufficient to
+     * hold the mappings in the given Map and a default load factor (0.75).
+     *
+     * @param t the map whose mappings are to be placed in this map.
+     * @throws NullPointerException if the specified map is null.
+     * @since   1.2
+     */
+    public Hashtable(Map<? extends K, ? extends V> t) {
+        this(Math.max(2*t.size(), 11), 0.75f);
+        putAll(t);
+    }
+
+    /**
+     * A constructor chained from {@link Properties} keeps Hashtable fields
+     * uninitialized since they are not used.
+     *
+     * @param dummy a dummy parameter
+     */
+    Hashtable(Void dummy) {}
+
+    /**
+     * Returns the number of keys in this hashtable.
+     *
+     * @return  the number of keys in this hashtable.
+     */
+    public synchronized int size() {
+        return count;
+    }
+
+    /**
+     * Tests if this hashtable maps no keys to values.
+     *
+     * @return  {@code true} if this hashtable maps no keys to values;
+     *          {@code false} otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return count == 0;
+    }
+
+    /**
+     * Returns an enumeration of the keys in this hashtable.
+     * Use the Enumeration methods on the returned object to fetch the keys
+     * sequentially. If the hashtable is structurally modified while enumerating
+     * over the keys then the results of enumerating are undefined.
+     *
+     * @return  an enumeration of the keys in this hashtable.
+     * @see     Enumeration
+     * @see     #elements()
+     * @see     #keySet()
+     * @see     Map
+     */
+    public synchronized Enumeration<K> keys() {
+        return this.<K>getEnumeration(KEYS);
+    }
+
+    /**
+     * Returns an enumeration of the values in this hashtable.
+     * Use the Enumeration methods on the returned object to fetch the elements
+     * sequentially. If the hashtable is structurally modified while enumerating
+     * over the values then the results of enumerating are undefined.
+     *
+     * @return  an enumeration of the values in this hashtable.
+     * @see     java.util.Enumeration
+     * @see     #keys()
+     * @see     #values()
+     * @see     Map
+     */
+    public synchronized Enumeration<V> elements() {
+        return this.<V>getEnumeration(VALUES);
+    }
+
+    /**
+     * Tests if some key maps into the specified value in this hashtable.
+     * This operation is more expensive than the {@link #containsKey
+     * containsKey} method.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue containsValue}, (which is part of the
+     * {@link Map} interface in the collections framework).
+     *
+     * @param      value   a value to search for
+     * @return     {@code true} if and only if some key maps to the
+     *             {@code value} argument in this hashtable as
+     *             determined by the {@code equals} method;
+     *             {@code false} otherwise.
+     * @throws     NullPointerException  if the value is {@code null}
+     */
+    public synchronized boolean contains(Object value) {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        HashtableEntry<?,?> tab[] = table;
+        for (int i = tab.length ; i-- > 0 ;) {
+            for (HashtableEntry<?,?> e = tab[i] ; e != null ; e = e.next) {
+                if (e.value.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this hashtable maps one or more keys to this value.
+     *
+     * <p>Note that this method is identical in functionality to {@link
+     * #contains contains} (which predates the {@link Map} interface).
+     *
+     * @param value value whose presence in this hashtable is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException  if the value is {@code null}
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        return contains(value);
+    }
+
+    /**
+     * Tests if the specified object is a key in this hashtable.
+     *
+     * @param   key   possible key
+     * @return  {@code true} if and only if the specified object
+     *          is a key in this hashtable, as determined by the
+     *          {@code equals} method; {@code false} otherwise.
+     * @throws  NullPointerException  if the key is {@code null}
+     * @see     #contains(Object)
+     */
+    public synchronized boolean containsKey(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key.equals(k))},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws NullPointerException if the specified key is null
+     * @see     #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized V get(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return (V)e.value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of and internally reorganizes this
+     * hashtable, in order to accommodate and access its entries more
+     * efficiently.  This method is called automatically when the
+     * number of keys in the hashtable exceeds this hashtable's capacity
+     * and load factor.
+     */
+    @SuppressWarnings("unchecked")
+    protected void rehash() {
+        int oldCapacity = table.length;
+        HashtableEntry<?,?>[] oldMap = table;
+
+        // overflow-conscious code
+        int newCapacity = (oldCapacity << 1) + 1;
+        if (newCapacity - MAX_ARRAY_SIZE > 0) {
+            if (oldCapacity == MAX_ARRAY_SIZE)
+                // Keep running with MAX_ARRAY_SIZE buckets
+                return;
+            newCapacity = MAX_ARRAY_SIZE;
+        }
+        HashtableEntry<?,?>[] newMap = new HashtableEntry<?,?>[newCapacity];
+
+        modCount++;
+        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        table = newMap;
+
+        for (int i = oldCapacity ; i-- > 0 ;) {
+            for (HashtableEntry<K,V> old = (HashtableEntry<K,V>)oldMap[i] ; old != null ; ) {
+                HashtableEntry<K,V> e = old;
+                old = old.next;
+
+                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+                e.next = (HashtableEntry<K,V>)newMap[index];
+                newMap[index] = e;
+            }
+        }
+    }
+
+    private void addEntry(int hash, K key, V value, int index) {
+        HashtableEntry<?,?> tab[] = table;
+        if (count >= threshold) {
+            // Rehash the table if the threshold is exceeded
+            rehash();
+
+            tab = table;
+            hash = key.hashCode();
+            index = (hash & 0x7FFFFFFF) % tab.length;
+        }
+
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>) tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+        modCount++;
+    }
+
+    /**
+     * Maps the specified {@code key} to the specified
+     * {@code value} in this hashtable. Neither the key nor the
+     * value can be {@code null}. <p>
+     *
+     * The value can be retrieved by calling the {@code get} method
+     * with a key that is equal to the original key.
+     *
+     * @param      key     the hashtable key
+     * @param      value   the value
+     * @return     the previous value of the specified key in this hashtable,
+     *             or {@code null} if it did not have one
+     * @throws     NullPointerException  if the key or value is
+     *               {@code null}
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     */
+    public synchronized V put(K key, V value) {
+        // Make sure the value is not null
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for(; entry != null ; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                entry.value = value;
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this
+     * hashtable. This method does nothing if the key is not in the hashtable.
+     *
+     * @param   key   the key that needs to be removed
+     * @return  the value to which the key had been mapped in this hashtable,
+     *          or {@code null} if the key did not have a mapping
+     * @throws  NullPointerException  if the key is {@code null}
+     */
+    public synchronized V remove(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for(HashtableEntry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                modCount++;
+                count--;
+                V oldValue = e.value;
+                e.value = null;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this hashtable.
+     * These mappings will replace any mappings that this hashtable had for any
+     * of the keys currently in the specified map.
+     *
+     * @param t mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     * @since 1.2
+     */
+    public synchronized void putAll(Map<? extends K, ? extends V> t) {
+        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Clears this hashtable so that it contains no keys.
+     */
+    public synchronized void clear() {
+        HashtableEntry<?,?> tab[] = table;
+        for (int index = tab.length; --index >= 0; )
+            tab[index] = null;
+        modCount++;
+        count = 0;
+    }
+
+    /**
+     * Creates a shallow copy of this hashtable. All the structure of the
+     * hashtable itself is copied, but the keys and values are not cloned.
+     * This is a relatively expensive operation.
+     *
+     * @return  a clone of the hashtable
+     */
+    public synchronized Object clone() {
+        Hashtable<?,?> t = cloneHashtable();
+        t.table = new HashtableEntry<?,?>[table.length];
+        for (int i = table.length ; i-- > 0 ; ) {
+            t.table[i] = (table[i] != null)
+                ? (HashtableEntry<?,?>) table[i].clone() : null;
+        }
+        t.keySet = null;
+        t.entrySet = null;
+        t.values = null;
+        t.modCount = 0;
+        return t;
+    }
+
+    /** Calls super.clone() */
+    final Hashtable<?,?> cloneHashtable() {
+        try {
+            return (Hashtable<?,?>)super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a string representation of this {@code Hashtable} object
+     * in the form of a set of entries, enclosed in braces and separated
+     * by the ASCII characters "<code> ,&nbsp;</code>" (comma and space). Each
+     * entry is rendered as the key, an equals sign {@code =}, and the
+     * associated element, where the {@code toString} method is used to
+     * convert the key and element to strings.
+     *
+     * @return  a string representation of this hashtable
+     */
+    public synchronized String toString() {
+        int max = size() - 1;
+        if (max == -1)
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        Iterator<Map.Entry<K,V>> it = entrySet().iterator();
+
+        sb.append('{');
+        for (int i = 0; ; i++) {
+            Map.Entry<K,V> e = it.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key.toString());
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value.toString());
+
+            if (i == max)
+                return sb.append('}').toString();
+            sb.append(", ");
+        }
+    }
+
+
+    private <T> Enumeration<T> getEnumeration(int type) {
+        if (count == 0) {
+            return Collections.emptyEnumeration();
+        } else {
+            return new Enumerator<>(type, false);
+        }
+    }
+
+    private <T> Iterator<T> getIterator(int type) {
+        if (count == 0) {
+            return Collections.emptyIterator();
+        } else {
+            return new Enumerator<>(type, true);
+        }
+    }
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     */
+    private transient volatile Set<K> keySet;
+    private transient volatile Set<Map.Entry<K,V>> entrySet;
+    private transient volatile Collection<V> values;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @since 1.2
+     */
+    public Set<K> keySet() {
+        if (keySet == null)
+            keySet = Collections.synchronizedSet(new KeySet(), this);
+        return keySet;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return getIterator(KEYS);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            return Hashtable.this.remove(o) != null;
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @since 1.2
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        if (entrySet==null)
+            entrySet = Collections.synchronizedSet(new EntrySet(), this);
+        return entrySet;
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return getIterator(ENTRIES);
+        }
+
+        public boolean add(Map.Entry<K,V> o) {
+            return super.add(o);
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> entry))
+                return false;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            for (HashtableEntry<?,?> e = tab[index]; e != null; e = e.next)
+                if (e.hash==hash && e.equals(entry))
+                    return true;
+            return false;
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> entry))
+                return false;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+            for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                if (e.hash==hash && e.equals(entry)) {
+                    if (prev != null)
+                        prev.next = e.next;
+                    else
+                        tab[index] = e.next;
+
+                    e.value = null; // clear for gc.
+                    modCount++;
+                    count--;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int size() {
+            return count;
+        }
+
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @since 1.2
+     */
+    public Collection<V> values() {
+        if (values==null)
+            values = Collections.synchronizedCollection(new ValueCollection(),
+                                                        this);
+        return values;
+    }
+
+    private class ValueCollection extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return getIterator(VALUES);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified Object with this Map for equality,
+     * as per the definition in the Map interface.
+     *
+     * @param  o object to be compared for equality with this hashtable
+     * @return true if the specified Object is equal to this Map
+     * @see Map#equals(Object)
+     * @since 1.2
+     */
+    public synchronized boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map<?, ?> t))
+            return false;
+        if (t.size() != size())
+            return false;
+
+        try {
+            for (Map.Entry<K, V> e : entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(t.get(key) == null && t.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(t.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException unused)   {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this Map as per the definition in the
+     * Map interface.
+     *
+     * @see Map#hashCode()
+     * @since 1.2
+     */
+    public synchronized int hashCode() {
+        /*
+         * This code detects the recursion caused by computing the hash code
+         * of a self-referential hash table and prevents the stack overflow
+         * that would otherwise result.  This allows certain 1.1-era
+         * applets with self-referential hash tables to work.  This code
+         * abuses the loadFactor field to do double-duty as a hashCode
+         * in progress flag, so as not to worsen the space performance.
+         * A negative load factor indicates that hash code computation is
+         * in progress.
+         */
+        int h = 0;
+        if (count == 0 || loadFactor < 0)
+            return h;  // Returns zero
+
+        loadFactor = -loadFactor;  // Mark hashCode computation in progress
+        HashtableEntry<?,?>[] tab = table;
+        for (HashtableEntry<?,?> entry : tab) {
+            while (entry != null) {
+                h += entry.hashCode();
+                entry = entry.next;
+            }
+        }
+
+        loadFactor = -loadFactor;  // Mark hashCode computation complete
+
+        return h;
+    }
+
+    @Override
+    public synchronized V getOrDefault(Object key, V defaultValue) {
+        V result = get(key);
+        return (null == result) ? defaultValue : result;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);     // explicit check required in case
+                                            // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<?, ?>[] tab = table;
+        for (HashtableEntry<?, ?> entry : tab) {
+            while (entry != null) {
+                action.accept((K)entry.key, (V)entry.value);
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);     // explicit check required in case
+                                              // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[])table;
+        for (HashtableEntry<K, V> entry : tab) {
+            while (entry != null) {
+                entry.value = Objects.requireNonNull(
+                    function.apply(entry.key, entry.value));
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @Override
+    public synchronized V putIfAbsent(K key, V value) {
+        Objects.requireNonNull(value);
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for (; entry != null; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                if (old == null) {
+                    entry.value = value;
+                }
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        Objects.requireNonNull(value);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                e.value = null; // clear for gc
+                modCount++;
+                count--;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean replace(K key, V oldValue, V newValue) {
+        Objects.requireNonNull(oldValue);
+        Objects.requireNonNull(newValue);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                if (e.value.equals(oldValue)) {
+                    e.value = newValue;
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized V replace(K key, V value) {
+        Objects.requireNonNull(value);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                V oldValue = e.value;
+                e.value = value;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the mapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * mapping function modified this map
+     */
+    @Override
+    public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                // Hashtable not accept null value
+                return e.value;
+            }
+        }
+
+        int mc = modCount;
+        V newValue = mappingFunction.apply(key);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                int mc = modCount;
+                V newValue = remappingFunction.apply(key, e.value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+                if (newValue == null) {
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    modCount = mc + 1;
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+        return null;
+    }
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && Objects.equals(e.key, key)) {
+                int mc = modCount;
+                V newValue = remappingFunction.apply(key, e.value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+                if (newValue == null) {
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    modCount = mc + 1;
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        int mc = modCount;
+        V newValue = remappingFunction.apply(key, null);
+        if (mc != modCount) { throw new ConcurrentModificationException(); }
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if the remapping
+     * function modified this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                int mc = modCount;
+                V newValue = remappingFunction.apply(e.value, value);
+                if (mc != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+                if (newValue == null) {
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    modCount = mc + 1;
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        if (value != null) {
+            addEntry(hash, key, value, index);
+        }
+
+        return value;
+    }
+
+    /**
+     * Save the state of the Hashtable to a stream (i.e., serialize it).
+     *
+     * @serialData The <i>capacity</i> of the Hashtable (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> of the Hashtable (the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping represented by the Hashtable
+     *             The key-value mappings are emitted in no particular order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws IOException {
+        writeHashtable(s);
+    }
+
+    /**
+     * Perform serialization of the Hashtable to an ObjectOutputStream.
+     * The Properties class overrides this method.
+     */
+    void writeHashtable(java.io.ObjectOutputStream s)
+            throws IOException {
+        HashtableEntry<Object, Object> entryStack = null;
+
+        synchronized (this) {
+            // Write out the threshold and loadFactor
+            s.defaultWriteObject();
+
+            // Write out the length and count of elements
+            s.writeInt(table.length);
+            s.writeInt(count);
+
+            // Stack copies of the entries in the table
+            for (HashtableEntry<?, ?> entry : table) {
+
+                while (entry != null) {
+                    entryStack =
+                        new HashtableEntry<>(0, entry.key, entry.value, entryStack);
+                    entry = entry.next;
+                }
+            }
+        }
+
+        // Write out the key/value objects from the stacked entries
+        while (entryStack != null) {
+            s.writeObject(entryStack.key);
+            s.writeObject(entryStack.value);
+            entryStack = entryStack.next;
+        }
+    }
+
+    /**
+     * Called by Properties to write out a simulated threshold and loadfactor.
+     */
+    final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length,
+            float loadFactor) throws IOException {
+        this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
+        this.loadFactor = loadFactor;
+        s.defaultWriteObject();
+    }
+
+    /**
+     * Reconstitute the Hashtable from a stream (i.e., deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+        readHashtable(s);
+    }
+
+    /**
+     * Perform deserialization of the Hashtable from an ObjectInputStream.
+     * The Properties class overrides this method.
+     */
+    void readHashtable(ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // Read and validate loadFactor (ignore threshold - it will be re-computed)
+        float lf = fields.get("loadFactor", 0.75f);
+        if (lf <= 0 || Float.isNaN(lf))
+            throw new StreamCorruptedException("Illegal load factor: " + lf);
+        lf = Math.min(Math.max(0.25f, lf), 4.0f);
+
+        // Read the original length of the array and number of elements
+        int origlength = s.readInt();
+        int elements = s.readInt();
+
+        // Validate # of elements
+        if (elements < 0)
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+
+        // Clamp original length to be more than elements / loadFactor
+        // (this is the invariant enforced with auto-growth)
+        origlength = Math.max(origlength, (int)(elements / lf) + 1);
+
+        // Compute new length with a bit of room 5% + 3 to grow but
+        // no larger than the clamped original length.  Make the length
+        // odd if it's large enough, this helps distribute the entries.
+        // Guard against the length ending up zero, that's not valid.
+        int length = (int)((elements + elements / 20) / lf) + 3;
+        if (length > elements && (length & 1) == 0)
+            length--;
+        length = Math.min(length, origlength);
+
+        if (length < 0) { // overflow
+            length = origlength;
+        }
+
+        // Check Map.Entry[].class since it's the nearest public type to
+        // what we're actually creating.
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length);
+        Hashtable.UnsafeHolder.putLoadFactor(this, lf);
+        table = new HashtableEntry<?,?>[length];
+        threshold = (int)Math.min(length * lf, MAX_ARRAY_SIZE + 1);
+        count = 0;
+
+        // Read the number of elements and then all the key/value objects
+        for (; elements > 0; elements--) {
+            @SuppressWarnings("unchecked")
+                K key = (K)s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V)s.readObject();
+            // sync is eliminated for performance
+            reconstitutionPut(table, key, value);
+        }
+    }
+
+    // Support for resetting final field during deserializing
+    private static final class UnsafeHolder {
+        private UnsafeHolder() { throw new InternalError(); }
+        private static final jdk.internal.misc.Unsafe unsafe
+                = jdk.internal.misc.Unsafe.getUnsafe();
+        private static final long LF_OFFSET
+                = unsafe.objectFieldOffset(Hashtable.class, "loadFactor");
+        static void putLoadFactor(Hashtable<?, ?> table, float lf) {
+            unsafe.putFloat(table, LF_OFFSET, lf);
+        }
+    }
+
+    /**
+     * The put method used by readObject. This is provided because put
+     * is overridable and should not be called in readObject since the
+     * subclass will not yet be initialized.
+     *
+     * <p>This differs from the regular put method in several ways. No
+     * checking for rehashing is necessary since the number of elements
+     * initially in the table is known. The modCount is not incremented and
+     * there's no synchronization because we are creating a new instance.
+     * Also, no return value is needed.
+     */
+    private void reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)
+        throws StreamCorruptedException
+    {
+        if (value == null) {
+            throw new java.io.StreamCorruptedException();
+        }
+        // Makes sure the key is not already in the hashtable.
+        // This should not happen in deserialized version.
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                throw new java.io.StreamCorruptedException();
+            }
+        }
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+    }
+
+    /**
+     * Hashtable bucket collision list entry
+     */
+    // BEGIN Android-changed: Renamed Entry -> HashtableEntry.
+    // Code references to "HashTable.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry which would break compilation
+    // of code like:
+    //
+    // Hashtable.Entry<K, V> entry = hashtable.entrySet().iterator.next();
+    //
+    // To compile, that code snippet's "HashtableMap.Entry" must
+    // mean java.util.Map.Entry which is the compile time type of
+    // entrySet()'s elements.
+    //
+    private static class HashtableEntry<K,V> implements Map.Entry<K,V> {
+    // END Android-changed: Renamed Entry -> HashtableEntry.
+        final int hash;
+        final K key;
+        V value;
+        HashtableEntry<K,V> next;
+
+        protected HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next) {
+            this.hash = hash;
+            this.key =  key;
+            this.value = value;
+            this.next = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected Object clone() {
+            return new HashtableEntry<>(hash, key, value,
+                                  (next==null ? null : (HashtableEntry<K,V>) next.clone()));
+        }
+
+        // Map.Entry Ops
+
+        public K getKey() {
+            return key;
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V value) {
+            if (value == null)
+                throw new NullPointerException();
+
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> e))
+                return false;
+
+            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
+               (value==null ? e.getValue()==null : value.equals(e.getValue()));
+        }
+
+        public int hashCode() {
+            return hash ^ Objects.hashCode(value);
+        }
+
+        public String toString() {
+            return key.toString()+"="+value.toString();
+        }
+    }
+
+    // Types of Enumerations/Iterations
+    private static final int KEYS = 0;
+    private static final int VALUES = 1;
+    private static final int ENTRIES = 2;
+
+    /**
+     * A hashtable enumerator class.  This class implements both the
+     * Enumeration and Iterator interfaces, but individual instances
+     * can be created with the Iterator methods disabled.  This is necessary
+     * to avoid unintentionally increasing the capabilities granted a user
+     * by passing an Enumeration.
+     */
+    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
+        HashtableEntry<?,?>[] table = Hashtable.this.table;
+        int index = table.length;
+        HashtableEntry<?,?> entry;
+        HashtableEntry<?,?> lastReturned;
+        final int type;
+
+        /**
+         * Indicates whether this Enumerator is serving as an Iterator
+         * or an Enumeration.  (true -> Iterator).
+         */
+        final boolean iterator;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Hashtable should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        protected int expectedModCount = Hashtable.this.modCount;
+
+        Enumerator(int type, boolean iterator) {
+            this.type = type;
+            this.iterator = iterator;
+        }
+
+        public boolean hasMoreElements() {
+            HashtableEntry<?,?> e = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (e == null && i > 0) {
+                e = t[--i];
+            }
+            entry = e;
+            index = i;
+            return e != null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T nextElement() {
+            HashtableEntry<?,?> et = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (et == null && i > 0) {
+                et = t[--i];
+            }
+            entry = et;
+            index = i;
+            if (et != null) {
+                HashtableEntry<?,?> e = lastReturned = entry;
+                entry = e.next;
+                return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
+            }
+            throw new NoSuchElementException("Hashtable Enumerator");
+        }
+
+        // Iterator methods
+        public boolean hasNext() {
+            return hasMoreElements();
+        }
+
+        public T next() {
+            if (Hashtable.this.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return nextElement();
+        }
+
+        public void remove() {
+            if (!iterator)
+                throw new UnsupportedOperationException();
+            if (lastReturned == null)
+                throw new IllegalStateException("Hashtable Enumerator");
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            synchronized(Hashtable.this) {
+                HashtableEntry<?,?>[] tab = Hashtable.this.table;
+                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
+
+                @SuppressWarnings("unchecked")
+                HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+                for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                    if (e == lastReturned) {
+                        if (prev == null)
+                            tab[index] = e.next;
+                        else
+                            prev.next = e.next;
+                        expectedModCount++;
+                        lastReturned = null;
+                        Hashtable.this.modCount++;
+                        Hashtable.this.count--;
+                        return;
+                    }
+                }
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/HexFormat.java b/android-35/java/util/HexFormat.java
new file mode 100644
index 0000000..b069c8c
--- /dev/null
+++ b/android-35/java/util/HexFormat.java
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+// BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+/*
+import jdk.internal.access.JavaLangAccess;
+import jdk.internal.access.SharedSecrets;
+*/
+// END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * {@code HexFormat} converts between bytes and chars and hex-encoded strings which may include
+ * additional formatting markup such as prefixes, suffixes, and delimiters.
+ * <p>
+ * There are two factories of {@code HexFormat} with preset parameters {@link #of()} and
+ * {@link #ofDelimiter(String) ofDelimiter(delimiter)}. For other parameter combinations
+ * the {@code withXXX} methods return copies of {@code HexFormat} modified
+ * {@link #withPrefix(String)}, {@link #withSuffix(String)}, {@link #withDelimiter(String)}
+ * or choice of {@link #withUpperCase()} or {@link #withLowerCase()} parameters.
+ * <p>
+ * For primitive to hexadecimal string conversions the {@code toHexDigits}
+ * methods include {@link #toHexDigits(byte)}, {@link #toHexDigits(int)}, and
+ * {@link #toHexDigits(long)}, etc. The default is to use lowercase characters {@code "0-9","a-f"}.
+ * For conversions producing uppercase hexadecimal the characters are {@code "0-9","A-F"}.
+ * Only the {@link HexFormat#isUpperCase() HexFormat.isUpperCase()} parameter is
+ * considered; the delimiter, prefix and suffix are not used.
+ *
+ * <p>
+ * For hexadecimal string to primitive conversions the {@code fromHexDigits}
+ * methods include {@link #fromHexDigits(CharSequence) fromHexDigits(string)},
+ * {@link #fromHexDigitsToLong(CharSequence) fromHexDigitsToLong(string)}, and
+ * {@link #fromHexDigit(int) fromHexDigit(int)} converts a single character or codepoint.
+ * For conversions from hexadecimal characters the digits and uppercase and lowercase
+ * characters in {@code "0-9", "a-f", and "A-F"} are converted to corresponding values
+ * {@code 0-15}. The delimiter, prefix, suffix, and uppercase parameters are not used.
+ *
+ * <p>
+ * For byte array to formatted hexadecimal string conversions
+ * the {@code formatHex} methods include {@link #formatHex(byte[]) formatHex(byte[])}
+ * and {@link #formatHex(Appendable, byte[]) formatHex(Appendable, byte[])}.
+ * The formatted output is a string or is appended to an {@link Appendable} such as
+ * {@link StringBuilder} or {@link java.io.PrintStream}.
+ * Each byte value is formatted as the prefix, two hexadecimal characters from the
+ * uppercase or lowercase digits, and the suffix.
+ * A delimiter follows each formatted value, except the last.
+ * For conversions producing uppercase hexadecimal strings use {@link #withUpperCase()}.
+ *
+ * <p>
+ * For formatted hexadecimal string to byte array conversions the
+ * {@code parseHex} methods include {@link #parseHex(CharSequence) parseHex(CharSequence)} and
+ * {@link #parseHex(char[], int, int) parseHex(char[], offset, length)}.
+ * Each byte value is parsed from the prefix, two case insensitive hexadecimal characters,
+ * and the suffix. A delimiter follows each formatted value, except the last.
+ *
+ * @apiNote
+ * For example, an individual byte is converted to a string of hexadecimal digits using
+ * {@link HexFormat#toHexDigits(int) toHexDigits(int)} and converted from a string to a
+ * primitive value using {@link HexFormat#fromHexDigits(CharSequence) fromHexDigits(string)}.
+ * <pre>{@code
+ *     HexFormat hex = HexFormat.of();
+ *     byte b = 127;
+ *     String byteStr = hex.toHexDigits(b);
+ *
+ *     byte byteVal = (byte)hex.fromHexDigits(byteStr);
+ *     assert(byteStr.equals("7f"));
+ *     assert(b == byteVal);
+ *
+ *     // The hexadecimal digits are: "7f"
+ * }</pre>
+ * <p>
+ * For a comma ({@code ", "}) separated format with a prefix ({@code "#"})
+ * using lowercase hex digits the {@code HexFormat} is:
+ * <pre>{@code
+ *     HexFormat commaFormat = HexFormat.ofDelimiter(", ").withPrefix("#");
+ *     byte[] bytes = {0, 1, 2, 3, 124, 125, 126, 127};
+ *     String str = commaFormat.formatHex(bytes);
+ *
+ *     byte[] parsed = commaFormat.parseHex(str);
+ *     assert(Arrays.equals(bytes, parsed));
+ *
+ *     // The formatted string is: "#00, #01, #02, #03, #7c, #7d, #7e, #7f"
+ * }</pre>
+ * <p>
+ * For a fingerprint of byte values that uses the delimiter colon ({@code ":"})
+ * and uppercase characters the {@code HexFormat} is:
+ * <pre>{@code
+ *     HexFormat formatFingerprint = HexFormat.ofDelimiter(":").withUpperCase();
+ *     byte[] bytes = {0, 1, 2, 3, 124, 125, 126, 127};
+ *     String str = formatFingerprint.formatHex(bytes);
+ *     byte[] parsed = formatFingerprint.parseHex(str);
+ *     assert(Arrays.equals(bytes, parsed));
+ *
+ *     // The formatted string is: "00:01:02:03:7C:7D:7E:7F"
+ * }</pre>
+ *
+ * <!-- Android-removed: paragraph on ValueBased
+ * <p>
+ * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code HexFormat} may have unpredictable results and should be avoided.
+ * The {@code equals} method should be used for comparisons.
+ * -->
+ *
+ * <p>
+ * This class is immutable and thread-safe.
+ * <p>
+ * Unless otherwise noted, passing a null argument to any method will cause a
+ * {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 17
+ */
+
+
+public final class HexFormat {
+
+    // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    /*
+    // Access to create strings from a byte array.
+    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+     */
+    // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+
+    private static final byte[] UPPERCASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+    };
+    private static final byte[] LOWERCASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+    };
+    // Analysis has shown that generating the whole array allows the JIT to generate
+    // better code compared to a slimmed down array, such as one cutting off after 'f'
+    private static final byte[] DIGITS = {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+            -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    };
+    /**
+     * Format each byte of an array as a pair of hexadecimal digits.
+     * The hexadecimal characters are from lowercase alpha digits.
+     */
+    private static final HexFormat HEX_FORMAT =
+            new HexFormat("", "", "", LOWERCASE_DIGITS);
+
+    private static final byte[] EMPTY_BYTES = {};
+
+    private final String delimiter;
+    private final String prefix;
+    private final String suffix;
+    private final byte[] digits;
+
+    /**
+     * Returns a HexFormat with a delimiter, prefix, suffix, and array of digits.
+     *
+     * @param delimiter a delimiter, non-null
+     * @param prefix a prefix, non-null
+     * @param suffix a suffix, non-null
+     * @param digits byte array of digits indexed by low nibble, non-null
+     * @throws NullPointerException if any argument is null
+     */
+    private HexFormat(String delimiter, String prefix, String suffix, byte[] digits) {
+        this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
+        this.prefix = Objects.requireNonNull(prefix, "prefix");
+        this.suffix = Objects.requireNonNull(suffix, "suffix");
+        this.digits = digits;
+    }
+
+    /**
+     * Returns a hexadecimal formatter with no delimiter and lowercase characters.
+     * The delimiter, prefix, and suffix are empty.
+     * The methods {@link #withDelimiter(String) withDelimiter},
+     * {@link #withUpperCase() withUpperCase}, {@link #withLowerCase() withLowerCase},
+     * {@link #withPrefix(String) withPrefix}, and {@link #withSuffix(String) withSuffix}
+     * return copies of formatters with new parameters.
+     *
+     * @return a hexadecimal formatter with no delimiter and lowercase characters
+     */
+    public static HexFormat of() {
+        return HEX_FORMAT;
+    }
+
+    /**
+     * Returns a hexadecimal formatter with the delimiter and lowercase characters.
+     * The prefix and suffix are empty.
+     * The methods {@link #withDelimiter(String) withDelimiter},
+     * {@link #withUpperCase() withUpperCase}, {@link #withLowerCase() withLowerCase},
+     * {@link #withPrefix(String) withPrefix}, and {@link #withSuffix(String) withSuffix}
+     * return copies of formatters with new parameters.
+     *
+     * @param delimiter a delimiter, non-null, may be empty
+     * @return a {@link HexFormat} with the delimiter and lowercase characters
+     */
+    public static HexFormat ofDelimiter(String delimiter) {
+        return new HexFormat(delimiter, "", "", LOWERCASE_DIGITS);
+    }
+
+    /**
+     * Returns a copy of this {@code HexFormat} with the delimiter.
+     * @param delimiter the delimiter, non-null, may be empty
+     * @return a copy of this {@code HexFormat} with the delimiter
+     */
+    public HexFormat withDelimiter(String delimiter) {
+        return new HexFormat(delimiter, this.prefix, this.suffix, this.digits);
+    }
+
+    /**
+     * Returns a copy of this {@code HexFormat} with the prefix.
+     *
+     * @param prefix a prefix, non-null, may be empty
+     * @return a copy of this {@code HexFormat} with the prefix
+     */
+    public HexFormat withPrefix(String prefix) {
+        return new HexFormat(this.delimiter, prefix, this.suffix, this.digits);
+    }
+
+    /**
+     * Returns a copy of this {@code HexFormat} with the suffix.
+     *
+     * @param suffix a suffix, non-null, may be empty
+     * @return a copy of this {@code HexFormat} with the suffix
+     */
+    public HexFormat withSuffix(String suffix) {
+        return new HexFormat(this.delimiter, this.prefix, suffix, this.digits);
+    }
+
+    /**
+     * Returns a copy of this {@code HexFormat} to use uppercase hexadecimal characters.
+     * The uppercase hexadecimal characters are {@code "0-9", "A-F"}.
+     *
+     * @return a copy of this {@code HexFormat} with uppercase hexadecimal characters
+     */
+    public HexFormat withUpperCase() {
+        return new HexFormat(this.delimiter, this.prefix, this.suffix, UPPERCASE_DIGITS);
+    }
+
+    /**
+     * Returns a copy of this {@code HexFormat} to use lowercase hexadecimal characters.
+     * The lowercase hexadecimal characters are {@code "0-9", "a-f"}.
+     *
+     * @return a copy of this {@code HexFormat} with lowercase hexadecimal characters
+     */
+    public HexFormat withLowerCase() {
+        return new HexFormat(this.delimiter, this.prefix, this.suffix, LOWERCASE_DIGITS);
+    }
+
+    /**
+     * Returns the delimiter between hexadecimal values in formatted hexadecimal strings.
+     *
+     * @return the delimiter, non-null, may be empty {@code ""}
+     */
+    public String delimiter() {
+        return delimiter;
+    }
+
+    /**
+     * Returns the prefix used for each hexadecimal value in formatted hexadecimal strings.
+     *
+     * @return the prefix, non-null, may be empty {@code ""}
+     */
+    public String prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the suffix used for each hexadecimal value in formatted hexadecimal strings.
+     *
+     * @return the suffix, non-null, may be empty {@code ""}
+     */
+    public String suffix() {
+        return suffix;
+    }
+
+    /**
+     * Returns {@code true} if the hexadecimal digits are uppercase,
+     * otherwise {@code false}.
+     *
+     * @return {@code true} if the hexadecimal digits are uppercase,
+     *          otherwise {@code false}
+     */
+    public boolean isUpperCase() {
+        return Arrays.equals(digits, UPPERCASE_DIGITS);
+    }
+
+    /**
+     * Returns a hexadecimal string formatted from a byte array.
+     * Each byte value is formatted as the prefix, two hexadecimal characters
+     * {@linkplain #isUpperCase selected from} uppercase or lowercase digits, and the suffix.
+     * A delimiter follows each formatted value, except the last.
+     *
+     * The behavior is equivalent to
+     * {@link #formatHex(byte[], int, int) formatHex(bytes, 0, bytes.length))}.
+     *
+     * @param bytes a non-null array of bytes
+     * @return a string hexadecimal formatting of the byte array
+     */
+    public String formatHex(byte[] bytes) {
+        return formatHex(bytes, 0, bytes.length);
+    }
+
+    /**
+     * Returns a hexadecimal string formatted from a byte array range.
+     * Each byte value is formatted as the prefix, two hexadecimal characters
+     * {@linkplain #isUpperCase selected from} uppercase or lowercase digits, and the suffix.
+     * A delimiter follows each formatted value, except the last.
+     *
+     * @param bytes a non-null array of bytes
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive
+     * @return a string hexadecimal formatting each byte of the array range
+     * @throws IndexOutOfBoundsException if the array range is out of bounds
+     */
+    public String formatHex(byte[] bytes, int fromIndex, int toIndex) {
+        Objects.requireNonNull(bytes,"bytes");
+        Objects.checkFromToIndex(fromIndex, toIndex, bytes.length);
+        if (toIndex - fromIndex == 0) {
+            return "";
+        }
+        // Format efficiently if possible
+        String s = formatOptDelimiter(bytes, fromIndex, toIndex);
+        if (s == null) {
+            long stride = prefix.length() + 2L + suffix.length() + delimiter.length();
+            int capacity = checkMaxArraySize((toIndex - fromIndex) * stride - delimiter.length());
+            StringBuilder sb = new StringBuilder(capacity);
+            formatHex(sb, bytes, fromIndex, toIndex);
+            s = sb.toString();
+        }
+        return s;
+    }
+
+    /**
+     * Appends formatted hexadecimal strings from a byte array to the {@link Appendable}.
+     * Each byte value is formatted as the prefix, two hexadecimal characters
+     * {@linkplain #isUpperCase selected from} uppercase or lowercase digits, and the suffix.
+     * A delimiter follows each formatted value, except the last.
+     * The formatted hexadecimal strings are appended in zero or more calls to the {@link Appendable} methods.
+     *
+     * @param <A> The type of {@code Appendable}
+     * @param out an {@code Appendable}, non-null
+     * @param bytes a byte array
+     * @return the {@code Appendable}
+     * @throws UncheckedIOException if an I/O exception occurs appending to the output
+     */
+    public <A extends Appendable> A formatHex(A out, byte[] bytes) {
+        return formatHex(out, bytes, 0, bytes.length);
+    }
+
+    /**
+     * Appends formatted hexadecimal strings from a byte array range to the {@link Appendable}.
+     * Each byte value is formatted as the prefix, two hexadecimal characters
+     * {@linkplain #isUpperCase selected from} uppercase or lowercase digits, and the suffix.
+     * A delimiter follows each formatted value, except the last.
+     * The formatted hexadecimal strings are appended in zero or more calls to the {@link Appendable} methods.
+     *
+     * @param <A> The type of {@code Appendable}
+     * @param out an {@code Appendable}, non-null
+     * @param bytes a byte array, non-null
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return the {@code Appendable}
+     * @throws IndexOutOfBoundsException if the array range is out of bounds
+     * @throws UncheckedIOException if an I/O exception occurs appending to the output
+     */
+    public <A extends Appendable> A formatHex(A out, byte[] bytes, int fromIndex, int toIndex) {
+        Objects.requireNonNull(out, "out");
+        Objects.requireNonNull(bytes, "bytes");
+        Objects.checkFromToIndex(fromIndex, toIndex, bytes.length);
+
+        int length = toIndex - fromIndex;
+        if (length > 0) {
+            try {
+                String between = suffix + delimiter + prefix;
+                out.append(prefix);
+                toHexDigits(out, bytes[fromIndex]);
+                if (between.isEmpty()) {
+                    for (int i = 1; i < length; i++) {
+                        toHexDigits(out, bytes[fromIndex + i]);
+                    }
+                } else {
+                    for (int i = 1; i < length; i++) {
+                        out.append(between);
+                        toHexDigits(out, bytes[fromIndex + i]);
+                    }
+                }
+                out.append(suffix);
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe.getMessage(), ioe);
+            }
+        }
+        return out;
+    }
+
+    /**
+     * Returns a string formatting of the range of bytes optimized
+     * for a single allocation.
+     * Prefix and suffix must be empty and the delimiter
+     * must be empty or a single byte character, otherwise null is returned.
+     *
+     * @param bytes the bytes, non-null
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return a String formatted or null for non-single byte delimiter
+     *         or non-empty prefix or suffix
+     */
+    private String formatOptDelimiter(byte[] bytes, int fromIndex, int toIndex) {
+        byte[] rep;
+        if (!prefix.isEmpty() || !suffix.isEmpty()) {
+            return null;
+        }
+        int length = toIndex - fromIndex;
+        if (delimiter.isEmpty()) {
+            // Allocate the byte array and fill in the hex pairs for each byte
+            rep = new byte[checkMaxArraySize(length * 2L)];
+            for (int i = 0; i < length; i++) {
+                rep[i * 2] = (byte)toHighHexDigit(bytes[fromIndex + i]);
+                rep[i * 2 + 1] = (byte)toLowHexDigit(bytes[fromIndex + i]);
+            }
+        } else if (delimiter.length() == 1 && delimiter.charAt(0) < 256) {
+            // Allocate the byte array and fill in the characters for the first byte
+            // Then insert the delimiter and hexadecimal characters for each of the remaining bytes
+            char sep = delimiter.charAt(0);
+            rep = new byte[checkMaxArraySize(length * 3L - 1L)];
+            rep[0] = (byte) toHighHexDigit(bytes[fromIndex]);
+            rep[1] = (byte) toLowHexDigit(bytes[fromIndex]);
+            for (int i = 1; i < length; i++) {
+                rep[i * 3 - 1] = (byte) sep;
+                rep[i * 3    ] = (byte) toHighHexDigit(bytes[fromIndex + i]);
+                rep[i * 3 + 1] = (byte) toLowHexDigit(bytes[fromIndex + i]);
+            }
+        } else {
+            // Delimiter formatting not to a single byte
+            return null;
+        }
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Checked that the requested size for the result string is
+     * less than or equal to the max array size.
+     *
+     * @param length the requested size of a byte array.
+     * @return the length
+     * @throws OutOfMemoryError if the size is larger than Integer.MAX_VALUE
+     */
+    private static int checkMaxArraySize(long length) {
+        if (length > Integer.MAX_VALUE)
+            throw new OutOfMemoryError("String size " + length +
+                    " exceeds maximum " + Integer.MAX_VALUE);
+        return (int)length;
+    }
+
+    /**
+     * Returns a byte array containing hexadecimal values parsed from the string.
+     *
+     * Each byte value is parsed from the prefix, two case insensitive hexadecimal characters,
+     * and the suffix. A delimiter follows each formatted value, except the last.
+     * The delimiters, prefixes, and suffixes strings must be present; they may be empty strings.
+     * A valid string consists only of the above format.
+     *
+     * @param string a string containing the byte values with prefix, hexadecimal digits, suffix,
+     *            and delimiters
+     * @return a byte array with the values parsed from the string
+     * @throws IllegalArgumentException if the prefix or suffix is not present for each byte value,
+     *          the byte values are not hexadecimal characters, or if the delimiter is not present
+     *          after all but the last byte value
+     */
+    public byte[] parseHex(CharSequence string) {
+        return parseHex(string, 0, string.length());
+    }
+
+    /**
+     * Returns a byte array containing hexadecimal values parsed from a range of the string.
+     *
+     * Each byte value is parsed from the prefix, two case insensitive hexadecimal characters,
+     * and the suffix. A delimiter follows each formatted value, except the last.
+     * The delimiters, prefixes, and suffixes strings must be present; they may be empty strings.
+     * A valid string consists only of the above format.
+     *
+     * @param string a string range containing hexadecimal digits,
+     *           delimiters, prefix, and suffix.
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return a byte array with the values parsed from the string range
+     * @throws IllegalArgumentException if the prefix or suffix is not present for each byte value,
+     *          the byte values are not hexadecimal characters, or if the delimiter is not present
+     *          after all but the last byte value
+     * @throws IndexOutOfBoundsException if the string range is out of bounds
+     */
+    public byte[] parseHex(CharSequence string, int fromIndex, int toIndex) {
+        Objects.requireNonNull(string, "string");
+        Objects.checkFromToIndex(fromIndex, toIndex, string.length());
+
+        if (fromIndex != 0 || toIndex != string.length()) {
+            string = string.subSequence(fromIndex, toIndex);
+        }
+
+        // BEGIN Android-changed: CharSequence#isEmpty() is not imported yet.
+        // See http://b/241413330.
+        /*
+        if (string.isEmpty())
+         */
+        if (string.length() == 0)
+        // END Android-changed: CharSequence#isEmpty() is not imported yet.
+            return EMPTY_BYTES;
+        if (delimiter.isEmpty() && prefix.isEmpty() && suffix.isEmpty())
+            return parseNoDelimiter(string);
+
+        // avoid overflow for max length prefix or suffix
+        long valueChars = prefix.length() + 2L + suffix.length();
+        long stride = valueChars + delimiter.length();
+        if ((string.length() - valueChars) % stride != 0)
+            throw new IllegalArgumentException("extra or missing delimiters " +
+                    "or values consisting of prefix, two hexadecimal digits, and suffix");
+
+        checkLiteral(string, 0, prefix);
+        checkLiteral(string, string.length() - suffix.length(), suffix);
+        String between = suffix + delimiter + prefix;
+        final int len = (int)((string.length() - valueChars) / stride + 1L);
+        byte[] bytes = new byte[len];
+        int i, offset;
+        for (i = 0, offset = prefix.length(); i < len - 1; i++, offset += 2 + between.length()) {
+            bytes[i] = (byte) fromHexDigits(string, offset);
+            checkLiteral(string, offset + 2, between);
+        }
+        bytes[i] = (byte) fromHexDigits(string, offset);
+
+        return bytes;
+    }
+
+    /**
+     * Returns a byte array containing hexadecimal values parsed from
+     * a range of the character array.
+     *
+     * Each byte value is parsed from the prefix, two case insensitive hexadecimal characters,
+     * and the suffix. A delimiter follows each formatted value, except the last.
+     * The delimiters, prefixes, and suffixes strings must be present; they may be empty strings.
+     * A valid character array range consists only of the above format.
+     *
+     * @param chars a character array range containing an even number of hexadecimal digits,
+     *          delimiters, prefix, and suffix.
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return a byte array with the values parsed from the character array range
+     * @throws IllegalArgumentException if the prefix or suffix is not present for each byte value,
+     *          the byte values are not hexadecimal characters, or if the delimiter is not present
+     *          after all but the last byte value
+     * @throws IndexOutOfBoundsException if the character array range is out of bounds
+     */
+    public byte[] parseHex(char[] chars, int fromIndex, int toIndex) {
+        Objects.requireNonNull(chars, "chars");
+        Objects.checkFromToIndex(fromIndex, toIndex, chars.length);
+        CharBuffer cb = CharBuffer.wrap(chars, fromIndex, toIndex - fromIndex);
+        return parseHex(cb);
+    }
+
+    /**
+     * Compare the literal and throw an exception if it does not match.
+     * Pre-condition:  {@code index + literal.length() <= string.length()}.
+     *
+     * @param string a CharSequence
+     * @param index the index of the literal in the CharSequence
+     * @param literal the expected literal
+     * @throws IllegalArgumentException if the literal is not present
+     */
+    private static void checkLiteral(CharSequence string, int index, String literal) {
+        assert index <= string.length() - literal.length()  : "pre-checked invariant error";
+        if (literal.isEmpty() ||
+                (literal.length() == 1 && literal.charAt(0) == string.charAt(index))) {
+            return;
+        }
+        for (int i = 0; i < literal.length(); i++) {
+            if (string.charAt(index + i) != literal.charAt(i)) {
+                throw new IllegalArgumentException(escapeNL("found: \"" +
+                        string.subSequence(index, index + literal.length()) +
+                        "\", expected: \"" + literal + "\", index: " + index +
+                        " ch: " + (int)string.charAt(index + i)));
+            }
+        }
+    }
+
+    /**
+     * Expands new line characters to escaped newlines for display.
+     *
+     * @param string a string
+     * @return a string with newline characters escaped
+     */
+    private static String escapeNL(String string) {
+        return string.replace("\n", "\\n")
+                .replace("\r", "\\r");
+    }
+
+    /**
+     * Returns the hexadecimal character for the low 4 bits of the value considering it to be a byte.
+     * If the parameter {@link #isUpperCase()} is {@code true} the
+     * character returned for values {@code 10-15} is uppercase {@code "A-F"},
+     * otherwise the character returned is lowercase {@code "a-f"}.
+     * The values in the range {@code 0-9} are returned as {@code "0-9"}.
+     *
+     * @param value a value, only the low 4 bits {@code 0-3} of the value are used
+     * @return the hexadecimal character for the low 4 bits {@code 0-3} of the value
+     */
+    public char toLowHexDigit(int value) {
+        return (char)digits[value & 0xf];
+    }
+
+    /**
+     * Returns the hexadecimal character for the high 4 bits of the value considering it to be a byte.
+     * If the parameter {@link #isUpperCase()} is {@code true} the
+     * character returned for values {@code 10-15} is uppercase {@code "A-F"},
+     * otherwise the character returned is lowercase {@code "a-f"}.
+     * The values in the range {@code 0-9} are returned as {@code "0-9"}.
+     *
+     * @param value a value, only bits {@code 4-7} of the value are used
+     * @return the hexadecimal character for the bits {@code 4-7} of the value
+     */
+    public char toHighHexDigit(int value) {
+        return (char)digits[(value >> 4) & 0xf];
+    }
+
+    /**
+     * Appends two hexadecimal characters for the byte value to the {@link Appendable}.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The hexadecimal characters are appended in one or more calls to the
+     * {@link Appendable} methods. The delimiter, prefix and suffix are not used.
+     *
+     * @param <A> The type of {@code Appendable}
+     * @param out an {@code Appendable}, non-null
+     * @param value a byte value
+     * @return the {@code Appendable}
+     * @throws UncheckedIOException if an I/O exception occurs appending to the output
+     */
+    public <A extends Appendable> A toHexDigits(A out, byte value) {
+        Objects.requireNonNull(out, "out");
+        try {
+            out.append(toHighHexDigit(value));
+            out.append(toLowHexDigit(value));
+            return out;
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe.getMessage(), ioe);
+        }
+    }
+
+    /**
+     * Returns the two hexadecimal characters for the {@code byte} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value a byte value
+     * @return the two hexadecimal characters for the byte value
+     */
+    public String toHexDigits(byte value) {
+        byte[] rep = new byte[2];
+        rep[0] = (byte)toHighHexDigit(value);
+        rep[1] = (byte)toLowHexDigit(value);
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Returns the four hexadecimal characters for the {@code char} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value a {@code char} value
+     * @return the four hexadecimal characters for the {@code char} value
+     */
+    public String toHexDigits(char value) {
+        return toHexDigits((short)value);
+    }
+
+    /**
+     * Returns the four hexadecimal characters for the {@code short} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value a {@code short} value
+     * @return the four hexadecimal characters for the {@code short} value
+     */
+    public String toHexDigits(short value) {
+        byte[] rep = new byte[4];
+        rep[0] = (byte)toHighHexDigit((byte)(value >> 8));
+        rep[1] = (byte)toLowHexDigit((byte)(value >> 8));
+        rep[2] = (byte)toHighHexDigit((byte)value);
+        rep[3] = (byte)toLowHexDigit((byte)value);
+
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Returns the eight hexadecimal characters for the {@code int} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value an {@code int} value
+     * @return the eight hexadecimal characters for the {@code int} value
+     * @see Integer#toHexString
+     */
+    public String toHexDigits(int value) {
+        byte[] rep = new byte[8];
+        rep[0] = (byte)toHighHexDigit((byte)(value >> 24));
+        rep[1] = (byte)toLowHexDigit((byte)(value >> 24));
+        rep[2] = (byte)toHighHexDigit((byte)(value >> 16));
+        rep[3] = (byte)toLowHexDigit((byte)(value >> 16));
+        rep[4] = (byte)toHighHexDigit((byte)(value >> 8));
+        rep[5] = (byte)toLowHexDigit((byte)(value >> 8));
+        rep[6] = (byte)toHighHexDigit((byte)value);
+        rep[7] = (byte)toLowHexDigit((byte)value);
+
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Returns the sixteen hexadecimal characters for the {@code long} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value a {@code long} value
+     * @return the sixteen hexadecimal characters for the {@code long} value
+     * @see Long#toHexString
+     */
+    public String toHexDigits(long value) {
+        byte[] rep = new byte[16];
+        rep[0] = (byte)toHighHexDigit((byte)(value >>> 56));
+        rep[1] = (byte)toLowHexDigit((byte)(value >>> 56));
+        rep[2] = (byte)toHighHexDigit((byte)(value >>> 48));
+        rep[3] = (byte)toLowHexDigit((byte)(value >>> 48));
+        rep[4] = (byte)toHighHexDigit((byte)(value >>> 40));
+        rep[5] = (byte)toLowHexDigit((byte)(value >>> 40));
+        rep[6] = (byte)toHighHexDigit((byte)(value >>> 32));
+        rep[7] = (byte)toLowHexDigit((byte)(value >>> 32));
+        rep[8] = (byte)toHighHexDigit((byte)(value >>> 24));
+        rep[9] = (byte)toLowHexDigit((byte)(value >>> 24));
+        rep[10] = (byte)toHighHexDigit((byte)(value >>> 16));
+        rep[11] = (byte)toLowHexDigit((byte)(value >>> 16));
+        rep[12] = (byte)toHighHexDigit((byte)(value >>> 8));
+        rep[13] = (byte)toLowHexDigit((byte)(value >>> 8));
+        rep[14] = (byte)toHighHexDigit((byte)value);
+        rep[15] = (byte)toLowHexDigit((byte)value);
+
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Returns up to sixteen hexadecimal characters for the {@code long} value.
+     * Each nibble (4 bits) from most significant to least significant of the value
+     * is formatted as if by {@link #toLowHexDigit(int) toLowHexDigit(nibble)}.
+     * The delimiter, prefix and suffix are not used.
+     *
+     * @param value a {@code long} value
+     * @param digits the number of hexadecimal digits to return, 0 to 16
+     * @return the hexadecimal characters for the {@code long} value
+     * @throws  IllegalArgumentException if {@code digits} is negative or greater than 16
+     */
+    public String toHexDigits(long value, int digits) {
+        if (digits < 0 || digits > 16)
+            throw new IllegalArgumentException("number of digits: " + digits);
+        if (digits == 0)
+            return "";
+        byte[] rep = new byte[digits];
+        for (int i = rep.length - 1; i >= 0; i--) {
+            rep[i] = (byte)toLowHexDigit((byte)(value));
+            value = value >>> 4;
+        }
+        // BEGIN Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+        /*
+        try {
+            // Return a new string using the bytes without making a copy
+            return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1);
+        } catch (CharacterCodingException cce) {
+            throw new AssertionError(cce);
+        }
+        */
+        return StringFactory.newStringFromBytes(rep, StandardCharsets.ISO_8859_1);
+        // END Android-removed: JavaLangAccess and SharedSecrets for String allocation.
+    }
+
+    /**
+     * Returns a byte array containing the parsed hex digits.
+     * A valid string consists only of an even number of hex digits.
+     *
+     * @param string a string containing an even number of only hex digits
+     * @return a byte array
+     * @throws IllegalArgumentException if the string length is not valid or
+     *          the string contains non-hexadecimal characters
+     */
+    private static byte[] parseNoDelimiter(CharSequence string) {
+        if ((string.length() & 1) != 0)
+            throw new IllegalArgumentException("string length not even: " +
+                    string.length());
+
+        byte[] bytes = new byte[string.length() / 2];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) fromHexDigits(string, i * 2);
+        }
+
+        return bytes;
+    }
+
+    /**
+     * Check the number of requested digits against a limit.
+     *
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @param limit the maximum allowed
+     * @return the length of the range
+     */
+    private static int checkDigitCount(int fromIndex, int toIndex, int limit) {
+        int length = toIndex - fromIndex;
+        if (length > limit)
+            throw new IllegalArgumentException("string length greater than " +
+                    limit + ": " + length);
+        return length;
+    }
+
+    /**
+     * Returns {@code true} if the character is a valid hexadecimal character or codepoint.
+     * The valid hexadecimal characters are:
+     * <ul>
+     * <li>{@code '0' ('\u005Cu0030')} through {@code '9' ('\u005Cu0039')} inclusive,
+     * <li>{@code 'A' ('\u005Cu0041')} through {@code 'F' ('\u005Cu0046')} inclusive, and
+     * <li>{@code 'a' ('\u005Cu0061')} through {@code 'f' ('\u005Cu0066')} inclusive.
+     * </ul>
+     * @param ch a codepoint
+     * @return {@code true} if the character is valid a hexadecimal character,
+     *          otherwise {@code false}
+     */
+    public static boolean isHexDigit(int ch) {
+        return ((ch >>> 8) == 0 && DIGITS[ch] >= 0);
+    }
+
+    /**
+     * Returns the value for the hexadecimal character or codepoint.
+     * The value is:
+     * <ul>
+     * <li>{@code (ch - '0')} for {@code '0'} through {@code '9'} inclusive,
+     * <li>{@code (ch - 'A' + 10)} for {@code 'A'} through {@code 'F'} inclusive, and
+     * <li>{@code (ch - 'a' + 10)} for {@code 'a'} through {@code 'f'} inclusive.
+     * </ul>
+     *
+     * @param ch a character or codepoint
+     * @return the value {@code 0-15}
+     * @throws  NumberFormatException if the codepoint is not a hexadecimal character
+     */
+    public static int fromHexDigit(int ch) {
+        int value;
+        if ((ch >>> 8) == 0 && (value = DIGITS[ch]) >= 0) {
+            return value;
+        }
+        throw new NumberFormatException("not a hexadecimal digit: \"" + (char) ch + "\" = " + ch);
+    }
+
+    /**
+     * Returns a value parsed from two hexadecimal characters in a string.
+     * The characters in the range from {@code index} to {@code index + 1},
+     * inclusive, must be valid hex digits according to {@link #fromHexDigit(int)}.
+     *
+     * @param string a CharSequence containing the characters
+     * @param index the index of the first character of the range
+     * @return the value parsed from the string range
+     * @throws  NumberFormatException if any of the characters in the range
+     *          is not a hexadecimal character
+     * @throws  IndexOutOfBoundsException if the range is out of bounds
+     *          for the {@code CharSequence}
+     */
+    private static int fromHexDigits(CharSequence string, int index) {
+        int high = fromHexDigit(string.charAt(index));
+        int low = fromHexDigit(string.charAt(index + 1));
+        return (high << 4) | low;
+    }
+
+    /**
+     * Returns the {@code int} value parsed from a string of up to eight hexadecimal characters.
+     * The hexadecimal characters are parsed from most significant to least significant
+     * using {@link #fromHexDigit(int)} to form an unsigned value.
+     * The value is zero extended to 32 bits and is returned as an {@code int}.
+     *
+     * @apiNote
+     * {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and
+     * {@link Integer#parseUnsignedInt(String, int) Integer.parseUnsignedInt(s, 16)}
+     * are similar but allow all Unicode hexadecimal digits defined by
+     * {@link Character#digit(char, int) Character.digit(ch, 16)}.
+     * {@code HexFormat} uses only hexadecimal characters
+     * {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
+     * Signed hexadecimal strings can be parsed with {@link Integer#parseInt(String, int)}.
+     *
+     * @param string a CharSequence containing up to eight hexadecimal characters
+     * @return the value parsed from the string
+     * @throws  IllegalArgumentException if the string length is greater than eight (8) or
+     *      if any of the characters is not a hexadecimal character
+     */
+    public static int fromHexDigits(CharSequence string) {
+        return fromHexDigits(string, 0, string.length());
+    }
+
+    /**
+     * Returns the {@code int} value parsed from a string range of up to eight hexadecimal
+     * characters.
+     * The characters in the range {@code fromIndex} to {@code toIndex}, exclusive,
+     * are parsed from most significant to least significant
+     * using {@link #fromHexDigit(int)} to form an unsigned value.
+     * The value is zero extended to 32 bits and is returned as an {@code int}.
+     *
+     * @apiNote
+     * {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and
+     * {@link Integer#parseUnsignedInt(String, int) Integer.parseUnsignedInt(s, 16)}
+     * are similar but allow all Unicode hexadecimal digits defined by
+     * {@link Character#digit(char, int) Character.digit(ch, 16)}.
+     * {@code HexFormat} uses only hexadecimal characters
+     * {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
+     * Signed hexadecimal strings can be parsed with {@link Integer#parseInt(String, int)}.
+     *
+     * @param string a CharSequence containing the characters
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return the value parsed from the string range
+     * @throws  IndexOutOfBoundsException if the range is out of bounds
+     *          for the {@code CharSequence}
+     * @throws  IllegalArgumentException if length of the range is greater than eight (8) or
+     *          if any of the characters is not a hexadecimal character
+     */
+    public static int fromHexDigits(CharSequence string, int fromIndex, int toIndex) {
+        Objects.requireNonNull(string, "string");
+        Objects.checkFromToIndex(fromIndex, toIndex, string.length());
+        int length = checkDigitCount(fromIndex, toIndex, 8);
+        int value = 0;
+        for (int i = 0; i < length; i++) {
+            value = (value << 4) + fromHexDigit(string.charAt(fromIndex + i));
+        }
+        return value;
+    }
+
+    /**
+     * Returns the long value parsed from a string of up to sixteen hexadecimal characters.
+     * The hexadecimal characters are parsed from most significant to least significant
+     * using {@link #fromHexDigit(int)} to form an unsigned value.
+     * The value is zero extended to 64 bits and is returned as a {@code long}.
+     *
+     * @apiNote
+     * {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and
+     * {@link Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s, 16)}
+     * are similar but allow all Unicode hexadecimal digits defined by
+     * {@link Character#digit(char, int) Character.digit(ch, 16)}.
+     * {@code HexFormat} uses only hexadecimal characters
+     * {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
+     * Signed hexadecimal strings can be parsed with {@link Long#parseLong(String, int)}.
+     *
+     * @param string a CharSequence containing up to sixteen hexadecimal characters
+     * @return the value parsed from the string
+     * @throws  IllegalArgumentException if the string length is greater than sixteen (16) or
+     *         if any of the characters is not a hexadecimal character
+     */
+    public static long fromHexDigitsToLong(CharSequence string) {
+        return fromHexDigitsToLong(string, 0, string.length());
+    }
+
+    /**
+     * Returns the long value parsed from a string range of up to sixteen hexadecimal
+     * characters.
+     * The characters in the range {@code fromIndex} to {@code toIndex}, exclusive,
+     * are parsed from most significant to least significant
+     * using {@link #fromHexDigit(int)} to form an unsigned value.
+     * The value is zero extended to 64 bits and is returned as a {@code long}.
+     *
+     * @apiNote
+     * {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and
+     * {@link Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s, 16)}
+     * are similar but allow all Unicode hexadecimal digits defined by
+     * {@link Character#digit(char, int) Character.digit(ch, 16)}.
+     * {@code HexFormat} uses only hexadecimal characters
+     * {@code "0-9"}, {@code "A-F"} and {@code "a-f"}.
+     * Signed hexadecimal strings can be parsed with {@link Long#parseLong(String, int)}.
+     *
+     * @param string a CharSequence containing the characters
+     * @param fromIndex the initial index of the range, inclusive
+     * @param toIndex the final index of the range, exclusive.
+     * @return the value parsed from the string range
+     * @throws  IndexOutOfBoundsException if the range is out of bounds
+     *          for the {@code CharSequence}
+     * @throws  IllegalArgumentException if the length of the range is greater than sixteen (16) or
+     *          if any of the characters is not a hexadecimal character
+     */
+    public static long fromHexDigitsToLong(CharSequence string, int fromIndex, int toIndex) {
+        Objects.requireNonNull(string, "string");
+        Objects.checkFromToIndex(fromIndex, toIndex, string.length());
+        int length = checkDigitCount(fromIndex, toIndex, 16);
+        long value = 0L;
+        for (int i = 0; i < length; i++) {
+            value = (value << 4) + fromHexDigit(string.charAt(fromIndex + i));
+        }
+        return value;
+    }
+
+    /**
+     * Returns {@code true} if the other object is a {@code HexFormat}
+     * with the same parameters.
+     *
+     * @param o an object, may be null
+     * @return {@code true} if the other object is a {@code HexFormat} and the parameters
+     *         uppercase, delimiter, prefix, and suffix are equal;
+     *         otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        HexFormat otherHex = (HexFormat) o;
+        return Arrays.equals(digits, otherHex.digits) &&
+                delimiter.equals(otherHex.delimiter) &&
+                prefix.equals(otherHex.prefix) &&
+                suffix.equals(otherHex.suffix);
+    }
+
+    /**
+     * Returns a hashcode for this {@code HexFormat}.
+     *
+     * @return a hashcode for this {@code HexFormat}
+     */
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(delimiter, prefix, suffix);
+        result = 31 * result + Boolean.hashCode(Arrays.equals(digits, UPPERCASE_DIGITS));
+        return result;
+    }
+
+    /**
+     * Returns a description of the formatter parameters for uppercase,
+     * delimiter, prefix, and suffix.
+     *
+     * @return a description of this {@code HexFormat}
+     */
+    @Override
+    public String toString() {
+        return escapeNL("uppercase: " + Arrays.equals(digits, UPPERCASE_DIGITS) +
+                ", delimiter: \"" + delimiter +
+                "\", prefix: \"" + prefix +
+                "\", suffix: \"" + suffix + "\"");
+    }
+}
diff --git a/android-35/java/util/IdentityHashMap.java b/android-35/java/util/IdentityHashMap.java
new file mode 100644
index 0000000..4795c30
--- /dev/null
+++ b/android-35/java/util/IdentityHashMap.java
@@ -0,0 +1,1600 @@
+/*
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * This class implements the {@code Map} interface with a hash table, using
+ * reference-equality in place of object-equality when comparing keys (and
+ * values).  In other words, in an {@code IdentityHashMap}, two keys
+ * {@code k1} and {@code k2} are considered equal if and only if
+ * {@code (k1==k2)}.  (In normal {@code Map} implementations (like
+ * {@code HashMap}) two keys {@code k1} and {@code k2} are considered equal
+ * if and only if {@code (k1==null ? k2==null : k1.equals(k2))}.)
+ *
+ * <p><b>This class is <i>not</i> a general-purpose {@code Map}
+ * implementation!  While this class implements the {@code Map} interface, it
+ * intentionally violates {@code Map's} general contract, which mandates the
+ * use of the {@code equals} method when comparing objects.  This class is
+ * designed for use only in the rare cases wherein reference-equality
+ * semantics are required.</b>
+ *
+ * <p>A typical use of this class is <i>topology-preserving object graph
+ * transformations</i>, such as serialization or deep-copying.  To perform such
+ * a transformation, a program must maintain a "node table" that keeps track
+ * of all the object references that have already been processed.  The node
+ * table must not equate distinct objects even if they happen to be equal.
+ * Another typical use of this class is to maintain <i>proxy objects</i>.  For
+ * example, a debugging facility might wish to maintain a proxy object for
+ * each object in the program being debugged.
+ *
+ * <p>This class provides all of the optional map operations, and permits
+ * {@code null} values and the {@code null} key.  This class makes no
+ * guarantees as to the order of the map; in particular, it does not guarantee
+ * that the order will remain constant over time.
+ *
+ * <p>This class provides constant-time performance for the basic
+ * operations ({@code get} and {@code put}), assuming the system
+ * identity hash function ({@link System#identityHashCode(Object)})
+ * disperses elements properly among the buckets.
+ *
+ * <p>This class has one tuning parameter (which affects performance but not
+ * semantics): <i>expected maximum size</i>.  This parameter is the maximum
+ * number of key-value mappings that the map is expected to hold.  Internally,
+ * this parameter is used to determine the number of buckets initially
+ * comprising the hash table.  The precise relationship between the expected
+ * maximum size and the number of buckets is unspecified.
+ *
+ * <p>If the size of the map (the number of key-value mappings) sufficiently
+ * exceeds the expected maximum size, the number of buckets is increased.
+ * Increasing the number of buckets ("rehashing") may be fairly expensive, so
+ * it pays to create identity hash maps with a sufficiently large expected
+ * maximum size.  On the other hand, iteration over collection views requires
+ * time proportional to the number of buckets in the hash table, so it
+ * pays not to set the expected maximum size too high if you are especially
+ * concerned with iteration performance or memory usage.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an identity hash map concurrently, and at
+ * least one of the threads modifies the map structurally, it <i>must</i>
+ * be synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
+ *
+ * <p>The iterators returned by the {@code iterator} method of the
+ * collections returned by all of this class's "collection view
+ * methods" are <i>fail-fast</i>: if the map is structurally modified
+ * at any time after the iterator is created, in any way except
+ * through the iterator's own {@code remove} method, the iterator
+ * will throw a {@link ConcurrentModificationException}.  Thus, in the
+ * face of concurrent modification, the iterator fails quickly and
+ * cleanly, rather than risking arbitrary, non-deterministic behavior
+ * at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>fail-fast iterators should be used only
+ * to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @implNote
+ * <p>This is a simple <i>linear-probe</i> hash table,
+ * as described for example in texts by Sedgewick and Knuth.  The array
+ * contains alternating keys and values, with keys at even indexes and values
+ * at odd indexes. (This arrangement has better locality for large
+ * tables than does using separate arrays.)  For many Java implementations
+ * and operation mixes, this class will yield better performance than
+ * {@link HashMap}, which uses <i>chaining</i> rather than linear-probing.
+ *
+ * @see     System#identityHashCode(Object)
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @author  Doug Lea and Josh Bloch
+ * @since   1.4
+ */
+
+public class IdentityHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V>, java.io.Serializable, Cloneable
+{
+    /**
+     * The initial capacity used by the no-args constructor.
+     * MUST be a power of two.  The value 32 corresponds to the
+     * (specified) expected maximum size of 21, given a load factor
+     * of 2/3.
+     */
+    private static final int DEFAULT_CAPACITY = 32;
+
+    /**
+     * The minimum capacity, used if a lower value is implicitly specified
+     * by either of the constructors with arguments.  The value 4 corresponds
+     * to an expected maximum size of 2, given a load factor of 2/3.
+     * MUST be a power of two.
+     */
+    private static final int MINIMUM_CAPACITY = 4;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<29.
+     *
+     * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
+     * because it has to have at least one slot with the key == null
+     * in order to avoid infinite loops in get(), put(), remove()
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 29;
+
+    /**
+     * The table, resized as necessary. Length MUST always be a power of two.
+     */
+    transient Object[] table; // non-private to simplify nested class access
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     *
+     * @serial
+     */
+    int size;
+
+    /**
+     * The number of modifications, to support fast-fail iterators
+     */
+    transient int modCount;
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null ? NULL_KEY : key);
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static final Object unmaskNull(Object key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Constructs a new, empty identity hash map with a default expected
+     * maximum size (21).
+     */
+    public IdentityHashMap() {
+        init(DEFAULT_CAPACITY);
+    }
+
+    /**
+     * Constructs a new, empty map with the specified expected maximum size.
+     * Putting more than the expected number of key-value mappings into
+     * the map may cause the internal data structure to grow, which may be
+     * somewhat time-consuming.
+     *
+     * @param expectedMaxSize the expected maximum size of the map
+     * @throws IllegalArgumentException if {@code expectedMaxSize} is negative
+     */
+    public IdentityHashMap(int expectedMaxSize) {
+        if (expectedMaxSize < 0)
+            throw new IllegalArgumentException("expectedMaxSize is negative: "
+                                               + expectedMaxSize);
+        init(capacity(expectedMaxSize));
+    }
+
+    /**
+     * Returns the appropriate capacity for the given expected maximum size.
+     * Returns the smallest power of two between MINIMUM_CAPACITY and
+     * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
+     * expectedMaxSize)/2, if such a number exists.  Otherwise returns
+     * MAXIMUM_CAPACITY.
+     */
+    private static int capacity(int expectedMaxSize) {
+        // assert expectedMaxSize >= 0;
+        return
+            (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+            (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+            Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
+    }
+
+    /**
+     * Initializes object to be an empty map with the specified initial
+     * capacity, which is assumed to be a power of two between
+     * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
+     */
+    private void init(int initCapacity) {
+        // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
+        // assert initCapacity >= MINIMUM_CAPACITY;
+        // assert initCapacity <= MAXIMUM_CAPACITY;
+
+        table = new Object[2 * initCapacity];
+    }
+
+    /**
+     * Constructs a new identity hash map containing the keys-value mappings
+     * in the specified map.
+     *
+     * @param m the map whose mappings are to be placed into this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public IdentityHashMap(Map<? extends K, ? extends V> m) {
+        // Allow for a bit of growth
+        this((int) ((1 + m.size()) * 1.1));
+        putAll(m);
+    }
+
+    /**
+     * Returns the number of key-value mappings in this identity hash map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this identity hash map contains no key-value
+     * mappings.
+     *
+     * @return {@code true} if this identity hash map contains no key-value
+     *         mappings
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns index for Object x.
+     */
+    private static int hash(Object x, int length) {
+        int h = System.identityHashCode(x);
+        // Multiply by -254 to use the hash LSB and to ensure index is even
+        return ((h << 1) - (h << 8)) & (length - 1);
+    }
+
+    /**
+     * Circularly traverses table of size len.
+     */
+    private static int nextKeyIndex(int i, int len) {
+        return (i + 2 < len ? i + 2 : 0);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public V get(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return (V) tab[i + 1];
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a key in this identity
+     * hash map.
+     *
+     * @param   key   possible key
+     * @return  {@code true} if the specified object reference is a key
+     *          in this map
+     * @see     #containsValue(Object)
+     */
+    public boolean containsKey(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return true;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a value in this identity
+     * hash map.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified object reference
+     * @see     #containsKey(Object)
+     */
+    public boolean containsValue(Object value) {
+        Object[] tab = table;
+        for (int i = 1; i < tab.length; i += 2)
+            if (tab[i] == value && tab[i - 1] != null)
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Tests if the specified key-value mapping is in the map.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  {@code true} if and only if the specified key-value
+     *          mapping is in the map
+     */
+    private boolean containsMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return tab[i + 1] == value;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Associates the specified value with the specified key in this identity
+     * hash map.  If the map previously contained a mapping for the key, the
+     * old value is replaced.
+     *
+     * @param key the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     * @see     #containsKey(Object)
+     */
+    public V put(K key, V value) {
+        final Object k = maskNull(key);
+
+        retryAfterResize: for (;;) {
+            final Object[] tab = table;
+            final int len = tab.length;
+            int i = hash(k, len);
+
+            for (Object item; (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                if (item == k) {
+                    @SuppressWarnings("unchecked")
+                        V oldValue = (V) tab[i + 1];
+                    tab[i + 1] = value;
+                    return oldValue;
+                }
+            }
+
+            final int s = size + 1;
+            // Use optimized form of 3 * s.
+            // Next capacity is len, 2 * current capacity.
+            if (s + (s << 1) > len && resize(len))
+                continue retryAfterResize;
+
+            modCount++;
+            tab[i] = k;
+            tab[i + 1] = value;
+            size = s;
+            return null;
+        }
+    }
+
+    /**
+     * Resizes the table if necessary to hold given capacity.
+     *
+     * @param newCapacity the new capacity, must be a power of two.
+     * @return whether a resize did in fact take place
+     */
+    private boolean resize(int newCapacity) {
+        // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
+        int newLength = newCapacity * 2;
+
+        Object[] oldTable = table;
+        int oldLength = oldTable.length;
+        if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
+            if (size == MAXIMUM_CAPACITY - 1)
+                throw new IllegalStateException("Capacity exhausted.");
+            return false;
+        }
+        if (oldLength >= newLength)
+            return false;
+
+        Object[] newTable = new Object[newLength];
+
+        for (int j = 0; j < oldLength; j += 2) {
+            Object key = oldTable[j];
+            if (key != null) {
+                Object value = oldTable[j+1];
+                oldTable[j] = null;
+                oldTable[j+1] = null;
+                int i = hash(key, newLength);
+                while (newTable[i] != null)
+                    i = nextKeyIndex(i, newLength);
+                newTable[i] = key;
+                newTable[i + 1] = value;
+            }
+        }
+        table = newTable;
+        return true;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int n = m.size();
+        if (n == 0)
+            return;
+        if (n > size)
+            resize(capacity(n)); // conservatively pre-expand
+
+        for (Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                modCount++;
+                size--;
+                @SuppressWarnings("unchecked")
+                    V oldValue = (V) tab[i + 1];
+                tab[i + 1] = null;
+                tab[i] = null;
+                closeDeletion(i);
+                return oldValue;
+            }
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Removes the specified key-value mapping from the map if it is present.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  {@code true} if and only if the specified key-value
+     *          mapping was in the map
+     */
+    private boolean removeMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                if (tab[i + 1] != value)
+                    return false;
+                modCount++;
+                size--;
+                tab[i] = null;
+                tab[i + 1] = null;
+                closeDeletion(i);
+                return true;
+            }
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Rehash all possibly-colliding entries following a
+     * deletion. This preserves the linear-probe
+     * collision properties required by get, put, etc.
+     *
+     * @param d the index of a newly empty deleted slot
+     */
+    private void closeDeletion(int d) {
+        // Adapted from Knuth Section 6.4 Algorithm R
+        Object[] tab = table;
+        int len = tab.length;
+
+        // Look for items to swap into newly vacated slot
+        // starting at index immediately following deletion,
+        // and continuing until a null slot is seen, indicating
+        // the end of a run of possibly-colliding keys.
+        Object item;
+        for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+             i = nextKeyIndex(i, len) ) {
+            // The following test triggers if the item at slot i (which
+            // hashes to be at slot r) should take the spot vacated by d.
+            // If so, we swap it in, and then continue with d now at the
+            // newly vacated i.  This process will terminate when we hit
+            // the null slot at the end of this run.
+            // The test is messy because we are using a circular table.
+            int r = hash(item, len);
+            if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
+                tab[d] = item;
+                tab[d + 1] = tab[i + 1];
+                tab[i] = null;
+                tab[i + 1] = null;
+                d = i;
+            }
+        }
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i++)
+            tab[i] = null;
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent identical object-reference mappings.  More formally, this
+     * map is equal to another map {@code m} if and only if
+     * {@code this.entrySet().equals(m.entrySet())}.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of this map it is
+     * possible that the symmetry and transitivity requirements of the
+     * {@code Object.equals} contract may be violated if this map is compared
+     * to a normal map.  However, the {@code Object.equals} contract is
+     * guaranteed to hold among {@code IdentityHashMap} instances.</b>
+     *
+     * @param  o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        } else if (o instanceof IdentityHashMap<?, ?> m) {
+            if (m.size() != size)
+                return false;
+
+            Object[] tab = m.table;
+            for (int i = 0; i < tab.length; i+=2) {
+                Object k = tab[i];
+                if (k != null && !containsMapping(k, tab[i + 1]))
+                    return false;
+            }
+            return true;
+        } else if (o instanceof Map<?, ?> m) {
+            return entrySet().equals(m.entrySet());
+        } else {
+            return false;  // o is not a Map
+        }
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * {@code entrySet()} view.  This ensures that {@code m1.equals(m2)}
+     * implies that {@code m1.hashCode()==m2.hashCode()} for any two
+     * {@code IdentityHashMap} instances {@code m1} and {@code m2}, as
+     * required by the general contract of {@link Object#hashCode}.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * {@code Map.Entry} instances in the set returned by this map's
+     * {@code entrySet} method, it is possible that the contractual
+     * requirement of {@code Object.hashCode} mentioned in the previous
+     * paragraph will be violated if one of the two objects being compared is
+     * an {@code IdentityHashMap} instance and the other is a normal map.</b>
+     *
+     * @return the hash code value for this map
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    public int hashCode() {
+        int result = 0;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i +=2) {
+            Object key = tab[i];
+            if (key != null) {
+                Object k = unmaskNull(key);
+                result += System.identityHashCode(k) ^
+                          System.identityHashCode(tab[i + 1]);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns a shallow copy of this identity hash map: the keys and values
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        try {
+            IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();
+            m.entrySet = null;
+            m.table = table.clone();
+            return m;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
+        int index = (size != 0 ? 0 : table.length); // current slot.
+        int expectedModCount = modCount; // to support fast-fail
+        int lastReturnedIndex = -1;      // to allow remove()
+        boolean indexValid; // To avoid unnecessary next computation
+        Object[] traversalTable = table; // reference to main table or copy
+
+        public boolean hasNext() {
+            Object[] tab = traversalTable;
+            for (int i = index; i < tab.length; i+=2) {
+                Object key = tab[i];
+                if (key != null) {
+                    index = i;
+                    return indexValid = true;
+                }
+            }
+            index = tab.length;
+            return false;
+        }
+
+        protected int nextIndex() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (!indexValid && !hasNext())
+                throw new NoSuchElementException();
+
+            indexValid = false;
+            lastReturnedIndex = index;
+            index += 2;
+            return lastReturnedIndex;
+        }
+
+        public void remove() {
+            if (lastReturnedIndex == -1)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            expectedModCount = ++modCount;
+            int deletedSlot = lastReturnedIndex;
+            lastReturnedIndex = -1;
+            // back up index to revisit new contents after deletion
+            index = deletedSlot;
+            indexValid = false;
+
+            // Removal code proceeds as in closeDeletion except that
+            // it must catch the rare case where an element already
+            // seen is swapped into a vacant slot that will be later
+            // traversed by this iterator. We cannot allow future
+            // next() calls to return it again.  The likelihood of
+            // this occurring under 2/3 load factor is very slim, but
+            // when it does happen, we must make a copy of the rest of
+            // the table to use for the rest of the traversal. Since
+            // this can only happen when we are near the end of the table,
+            // even in these rare cases, this is not very expensive in
+            // time or space.
+
+            Object[] tab = traversalTable;
+            int len = tab.length;
+
+            int d = deletedSlot;
+            Object key = tab[d];
+            tab[d] = null;        // vacate the slot
+            tab[d + 1] = null;
+
+            // If traversing a copy, remove in real table.
+            // We can skip gap-closure on copy.
+            if (tab != IdentityHashMap.this.table) {
+                IdentityHashMap.this.remove(key);
+                expectedModCount = modCount;
+                return;
+            }
+
+            size--;
+
+            Object item;
+            for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                int r = hash(item, len);
+                // See closeDeletion for explanation of this conditional
+                if ((i < r && (r <= d || d <= i)) ||
+                    (r <= d && d <= i)) {
+
+                    // If we are about to swap an already-seen element
+                    // into a slot that may later be returned by next(),
+                    // then clone the rest of table for use in future
+                    // next() calls. It is OK that our copy will have
+                    // a gap in the "wrong" place, since it will never
+                    // be used for searching anyway.
+
+                    if (i < deletedSlot && d >= deletedSlot &&
+                        traversalTable == IdentityHashMap.this.table) {
+                        int remaining = len - deletedSlot;
+                        Object[] newTable = new Object[remaining];
+                        System.arraycopy(tab, deletedSlot,
+                                         newTable, 0, remaining);
+                        traversalTable = newTable;
+                        index = 0;
+                    }
+
+                    tab[d] = item;
+                    tab[d + 1] = tab[i + 1];
+                    tab[i] = null;
+                    tab[i + 1] = null;
+                    d = i;
+                }
+            }
+        }
+    }
+
+    private class KeyIterator extends IdentityHashMapIterator<K> {
+        @SuppressWarnings("unchecked")
+        public K next() {
+            return (K) unmaskNull(traversalTable[nextIndex()]);
+        }
+    }
+
+    private class ValueIterator extends IdentityHashMapIterator<V> {
+        @SuppressWarnings("unchecked")
+        public V next() {
+            return (V) traversalTable[nextIndex() + 1];
+        }
+    }
+
+    private class EntryIterator
+        extends IdentityHashMapIterator<Map.Entry<K,V>>
+    {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            lastReturnedEntry = new Entry(nextIndex());
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            @SuppressWarnings("unchecked")
+            public K getKey() {
+                checkIndexForEntryUse();
+                return (K) unmaskNull(traversalTable[index]);
+            }
+
+            @SuppressWarnings("unchecked")
+            public V getValue() {
+                checkIndexForEntryUse();
+                return (V) traversalTable[index+1];
+            }
+
+            @SuppressWarnings("unchecked")
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = (V) traversalTable[index+1];
+                traversalTable[index+1] = value;
+                // if shadowing, force into main table
+                if (traversalTable != IdentityHashMap.this.table)
+                    put((K) traversalTable[index], value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return super.equals(o);
+
+                return o instanceof Map.Entry<?, ?> e
+                        && e.getKey() == unmaskNull(traversalTable[index])
+                        && e.getValue() == traversalTable[index+1];
+            }
+
+            public int hashCode() {
+                if (lastReturnedIndex < 0)
+                    return super.hashCode();
+
+                return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
+                       System.identityHashCode(traversalTable[index+1]));
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return (unmaskNull(traversalTable[index]) + "="
+                        + traversalTable[index+1]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns an identity-based set view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress, the results of the iteration are
+     * undefined.  The set supports element removal, which removes the
+     * corresponding mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll}, and
+     * {@code clear} methods.  It does not support the {@code add} or
+     * {@code addAll} methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * {@code Set} interface, it does <i>not</i> obey {@code Set's} general
+     * contract.  Like its backing map, the set returned by this method
+     * defines element equality as reference-equality rather than
+     * object-equality.  This affects the behavior of its {@code contains},
+     * {@code remove}, {@code containsAll}, {@code equals}, and
+     * {@code hashCode} methods.</b>
+     *
+     * <p><b>The {@code equals} method of the returned set returns {@code true}
+     * only if the specified object is a set containing exactly the same
+     * object references as the returned set.  The symmetry and transitivity
+     * requirements of the {@code Object.equals} contract may be violated if
+     * the set returned by this method is compared to a normal set.  However,
+     * the {@code Object.equals} contract is guaranteed to hold among sets
+     * returned by this method.</b>
+     *
+     * <p>The {@code hashCode} method of the returned set returns the sum of
+     * the <i>identity hashcodes</i> of the elements in the set, rather than
+     * the sum of their hashcodes.  This is mandated by the change in the
+     * semantics of the {@code equals} method, in order to enforce the
+     * general contract of the {@code Object.hashCode} method among sets
+     * returned by this method.
+     *
+     * @return an identity-based set view of the keys contained in this map
+     * @see Object#equals(Object)
+     * @see System#identityHashCode(Object)
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            IdentityHashMap.this.remove(o);
+            return size != oldSize;
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<K> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public int hashCode() {
+            int result = 0;
+            for (K key : this)
+                result += System.identityHashCode(key);
+            return result;
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) unmaskNull(key); // unmask key
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress,
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} methods.  It does not
+     * support the {@code add} or {@code addAll} methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * {@code Collection} interface, it does <i>not</i> obey
+     * {@code Collection's} general contract.  Like its backing map,
+     * the collection returned by this method defines element equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of its {@code contains}, {@code remove} and
+     * {@code containsAll} methods.</b>
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            for (Iterator<V> i = iterator(); i.hasNext(); ) {
+                if (i.next() == o) {
+                    i.remove();
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                if (tab[si] != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) tab[si+1]; // copy value
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * Each element in the returned set is a reference-equality-based
+     * {@code Map.Entry}.  The set is backed by the map, so changes
+     * to the map are reflected in the set, and vice-versa.  If the
+     * map is modified while an iteration over the set is in progress,
+     * the results of the iteration are undefined.  The set supports
+     * element removal, which removes the corresponding mapping from
+     * the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll} and {@code clear}
+     * methods.  It does not support the {@code add} or
+     * {@code addAll} methods.
+     *
+     * <p>Like the backing map, the {@code Map.Entry} objects in the set
+     * returned by this method define key and value equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of the {@code equals} and {@code hashCode} methods of these
+     * {@code Map.Entry} objects.  A reference-equality based {@code Map.Entry
+     * e} is equal to an object {@code o} if and only if {@code o} is a
+     * {@code Map.Entry} and {@code e.getKey()==o.getKey() &&
+     * e.getValue()==o.getValue()}.  To accommodate these equals
+     * semantics, the {@code hashCode} method returns
+     * {@code System.identityHashCode(e.getKey()) ^
+     * System.identityHashCode(e.getValue())}.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * {@code Map.Entry} instances in the set returned by this method,
+     * it is possible that the symmetry and transitivity requirements of
+     * the {@link Object#equals(Object)} contract may be violated if any of
+     * the entries in the set is compared to a normal map entry, or if
+     * the set returned by this method is compared to a set of normal map
+     * entries (such as would be returned by a call to this method on a normal
+     * map).  However, the {@code Object.equals} contract is guaranteed to
+     * hold among identity-based map entries, and among sets of such entries.
+     * </b>
+     *
+     * @return a set view of the identity-mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public boolean contains(Object o) {
+            return o instanceof Entry<?, ?> entry
+                    && containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            return o instanceof Entry<?, ?> entry
+                    && removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]);
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 8188218128353913216L;
+
+    /**
+     * Saves the state of the {@code IdentityHashMap} instance to a stream
+     * (i.e., serializes it).
+     *
+     * @serialData The <i>size</i> of the HashMap (the number of key-value
+     *          mappings) ({@code int}), followed by the key (Object) and
+     *          value (Object) for each key-value mapping represented by the
+     *          IdentityHashMap.  The key-value mappings are emitted in no
+     *          particular order.
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream s)
+        throws java.io.IOException  {
+        // Write out size (number of mappings) and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size again (maintained for backward compatibility)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i += 2) {
+            Object key = tab[i];
+            if (key != null) {
+                s.writeObject(unmaskNull(key));
+                s.writeObject(tab[i + 1]);
+            }
+        }
+    }
+
+    /**
+     * Reconstitutes the {@code IdentityHashMap} instance from a stream (i.e.,
+     * deserializes it).
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException  {
+        // Size (number of mappings) is written to the stream twice
+        // Read first size value and ignore it
+        s.readFields();
+
+        // Read second size value, validate and assign to size field
+        int size = s.readInt();
+        if (size < 0)
+            throw new java.io.StreamCorruptedException
+                ("Illegal mappings count: " + size);
+        int cap = capacity(size);
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap*2);
+        this.size = size;
+        init(cap);
+
+        // Read the keys and values, and put the mappings in the table
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                K key = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V) s.readObject();
+            putForCreate(key, value);
+        }
+    }
+
+    /**
+     * The put method for readObject.  It does not resize the table,
+     * update modCount, etc.
+     */
+    private void putForCreate(K key, V value)
+        throws java.io.StreamCorruptedException
+    {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        Object item;
+        while ( (item = tab[i]) != null) {
+            if (item == k)
+                throw new java.io.StreamCorruptedException();
+            i = nextKeyIndex(i, len);
+        }
+        tab[i] = k;
+        tab[i + 1] = value;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                action.accept((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Similar form as array-based Spliterators, but skips blank elements,
+     * and guestimates size as decreasing by half per split.
+     */
+    static class IdentityHashMapSpliterator<K,V> {
+        final IdentityHashMap<K,V> map;
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // initialized when fence set
+
+        IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin,
+                                   int fence, int est, int expectedModCount) {
+            this.map = map;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                est = map.size;
+                expectedModCount = map.modCount;
+                hi = fence = map.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(map, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                     expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc; Object key;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if ((key = a[i]) != null)
+                        action.accept((K)unmaskNull(key));
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                index += 2;
+                if (key != null) {
+                    action.accept((K)unmaskNull(key));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
+                                       expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if (a[i] != null) {
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept(v);
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    action.accept(v);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0);
+        }
+
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                       expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    Object key = a[i];
+                    if (key != null) {
+                        @SuppressWarnings("unchecked") K k =
+                            (K)unmaskNull(key);
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept
+                            (new AbstractMap.SimpleImmutableEntry<>(k, v));
+
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    @SuppressWarnings("unchecked") K k =
+                        (K)unmaskNull(key);
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<>(k, v));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/android-35/java/util/IllegalFormatArgumentIndexException.java b/android-35/java/util/IllegalFormatArgumentIndexException.java
new file mode 100644
index 0000000..02d5449
--- /dev/null
+++ b/android-35/java/util/IllegalFormatArgumentIndexException.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the argument index is not within the valid
+ * range of supported argument index values. If an index value isn't
+ * representable by an {@code int} type, then the value
+ * {@code Integer.MIN_VALUE} will be used in the exception.
+ *
+ * @since 16
+ */
+class IllegalFormatArgumentIndexException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 4191767811181838112L;
+
+    private final int illegalIndex;
+
+    /**
+     * Constructs an instance of this class with the specified argument index
+     * @param index The value of a corresponding illegal argument index.
+     */
+    IllegalFormatArgumentIndexException(int index) {
+        illegalIndex = index;
+    }
+
+    /**
+     * Gets the value of the illegal index.
+     * Returns {@code Integer.MIN_VALUE} if the illegal index is not
+     * representable by an {@code int}.
+     * @return the illegal index value
+     */
+    int getIndex() {
+        return illegalIndex;
+    }
+
+    @Override
+    public String getMessage() {
+        int index = getIndex();
+
+        if (index == Integer.MIN_VALUE) {
+           return "Format argument index: (not representable as int)";
+        }
+
+        return String.format("Illegal format argument index = %d", getIndex());
+    }
+
+}
diff --git a/android-35/java/util/IllegalFormatCodePointException.java b/android-35/java/util/IllegalFormatCodePointException.java
new file mode 100644
index 0000000..14ec913
--- /dev/null
+++ b/android-35/java/util/IllegalFormatCodePointException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a character with an invalid Unicode code
+ * point as defined by {@link Character#isValidCodePoint} is passed to the
+ * {@link Formatter}.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatCodePointException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 19080630L;
+
+    private int c;
+
+    /**
+     * Constructs an instance of this class with the specified illegal code
+     * point as defined by {@link Character#isValidCodePoint}.
+     *
+     * @param  c
+     *         The illegal Unicode code point
+     */
+    public IllegalFormatCodePointException(int c) {
+        this.c = c;
+    }
+
+    /**
+     * Returns the illegal code point as defined by {@link
+     * Character#isValidCodePoint}.
+     *
+     * @return  The illegal Unicode code point
+     */
+    public int getCodePoint() {
+        return c;
+    }
+
+    public String getMessage() {
+        return String.format("Code point = %#x", c);
+    }
+}
diff --git a/android-35/java/util/IllegalFormatConversionException.java b/android-35/java/util/IllegalFormatConversionException.java
new file mode 100644
index 0000000..2dacf20
--- /dev/null
+++ b/android-35/java/util/IllegalFormatConversionException.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the argument corresponding to the format
+ * specifier is of an incompatible type.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatConversionException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 17000126L;
+
+    private char c;
+    private Class<?> arg;
+
+    /**
+     * Constructs an instance of this class with the mismatched conversion and
+     * the corresponding argument class.
+     *
+     * @param  c
+     *         Inapplicable conversion
+     *
+     * @param  arg
+     *         Class of the mismatched argument
+     */
+    public IllegalFormatConversionException(char c, Class<?> arg) {
+        if (arg == null)
+            throw new NullPointerException();
+        this.c = c;
+        this.arg = arg;
+    }
+
+    /**
+     * Returns the inapplicable conversion.
+     *
+     * @return  The inapplicable conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    /**
+     * Returns the class of the mismatched argument.
+     *
+     * @return   The class of the mismatched argument
+     */
+    public Class<?> getArgumentClass() {
+        return arg;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("%c != %s", c, arg.getName());
+    }
+}
diff --git a/android-35/java/util/IllegalFormatException.java b/android-35/java/util/IllegalFormatException.java
new file mode 100644
index 0000000..97b85cc
--- /dev/null
+++ b/android-35/java/util/IllegalFormatException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a format string contains an illegal syntax
+ * or a format specifier that is incompatible with the given arguments.  Only
+ * explicit subtypes of this exception which correspond to specific errors
+ * should be instantiated.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatException extends IllegalArgumentException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 18830826L;
+
+    // package-private to prevent explicit instantiation
+    IllegalFormatException() { }
+}
diff --git a/android-35/java/util/IllegalFormatFlagsException.java b/android-35/java/util/IllegalFormatFlagsException.java
new file mode 100644
index 0000000..38e4e2d
--- /dev/null
+++ b/android-35/java/util/IllegalFormatFlagsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an illegal combination flags is given.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatFlagsException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 790824L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an illegal combination
+     */
+    public IllegalFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an illegal combination.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return "Flags = '" + flags + "'";
+    }
+}
diff --git a/android-35/java/util/IllegalFormatPrecisionException.java b/android-35/java/util/IllegalFormatPrecisionException.java
new file mode 100644
index 0000000..bdf3de6
--- /dev/null
+++ b/android-35/java/util/IllegalFormatPrecisionException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the precision is a negative value other than
+ * {@code -1}, the conversion does not support a precision, or the value is
+ * otherwise unsupported. If the precision is not representable by an
+ * {@code int} type, then the value {@code Integer.MIN_VALUE} will be used
+ * in the exception.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatPrecisionException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 18711008L;
+
+    private int p;
+
+    /**
+     * Constructs an instance of this class with the specified precision.
+     *
+     * @param  p
+     *         The precision
+     */
+    public IllegalFormatPrecisionException(int p) {
+        this.p = p;
+    }
+
+    /**
+     * Returns the precision. If the precision isn't representable by an
+     * {@code int}, then will return {@code Integer.MIN_VALUE}.
+     *
+     * @return  The precision
+     */
+    public int getPrecision() {
+        return p;
+    }
+
+    public String getMessage() {
+        return Integer.toString(p);
+    }
+}
diff --git a/android-35/java/util/IllegalFormatWidthException.java b/android-35/java/util/IllegalFormatWidthException.java
new file mode 100644
index 0000000..e00ec01
--- /dev/null
+++ b/android-35/java/util/IllegalFormatWidthException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is a negative value other
+ * than {@code -1} or is otherwise unsupported. If a given format width is not
+ * representable by an {@code int} type, then the value
+ * {@code Integer.MIN_VALUE} will be used in the exception.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatWidthException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 16660902L;
+
+    private int w;
+
+    /**
+     * Constructs an instance of this class with the specified width.
+     *
+     * @param  w
+     *         The width
+     */
+    public IllegalFormatWidthException(int w) {
+        this.w = w;
+    }
+
+    /**
+     * Returns the width. If the width is not representable by an {@code int},
+     * then returns {@code Integer.MIN_VALUE}.
+     *
+     * @return  The width
+     */
+    public int getWidth() {
+        return w;
+    }
+
+    public String getMessage() {
+        return Integer.toString(w);
+    }
+}
diff --git a/android-35/java/util/IllformedLocaleException.java b/android-35/java/util/IllformedLocaleException.java
new file mode 100644
index 0000000..47febaa
--- /dev/null
+++ b/android-35/java/util/IllformedLocaleException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in {@link Locale} and {@link Locale.Builder} to
+ * indicate that an argument is not a well-formed BCP 47 tag.
+ *
+ * @see Locale
+ * @since 1.7
+ */
+public class IllformedLocaleException extends RuntimeException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = -5245986824925681401L;
+
+    private int _errIdx = -1;
+
+    /**
+     * Constructs a new {@code IllformedLocaleException} with no
+     * detail message and -1 as the error index.
+     */
+    public IllformedLocaleException() {
+        super();
+    }
+
+    /**
+     * Constructs a new {@code IllformedLocaleException} with the
+     * given message and -1 as the error index.
+     *
+     * @param message the message
+     */
+    public IllformedLocaleException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code IllformedLocaleException} with the
+     * given message and the error index.  The error index is the approximate
+     * offset from the start of the ill-formed value to the point where the
+     * parse first detected an error.  A negative error index value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @param message the message
+     * @param errorIndex the index
+     */
+    public IllformedLocaleException(String message, int errorIndex) {
+        super(message + ((errorIndex < 0) ? "" : " [at index " + errorIndex + "]"));
+        _errIdx = errorIndex;
+    }
+
+    /**
+     * Returns the index where the error was found. A negative value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @return the error index
+     */
+    public int getErrorIndex() {
+        return _errIdx;
+    }
+}
diff --git a/android-35/java/util/ImmutableCollections.java b/android-35/java/util/ImmutableCollections.java
new file mode 100644
index 0000000..d3bfb33
--- /dev/null
+++ b/android-35/java/util/ImmutableCollections.java
@@ -0,0 +1,1536 @@
+/*
+ * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.access.JavaUtilCollectionAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * Container class for immutable collections. Not part of the public API.
+ * Mainly for namespace management and shared infrastructure.
+ *
+ * Serial warnings are suppressed throughout because all implementation
+ * classes use a serial proxy and thus have no need to declare serialVersionUID.
+ */
+@SuppressWarnings("serial")
+class ImmutableCollections {
+    /**
+     * A "salt" value used for randomizing iteration order. This is initialized once
+     * and stays constant for the lifetime of the JVM. It need not be truly random, but
+     * it needs to vary sufficiently from one run to the next so that iteration order
+     * will vary between JVM runs.
+     */
+    private static final long SALT32L;
+
+    /**
+     * For set and map iteration, we will iterate in "reverse" stochastically,
+     * decided at bootstrap time.
+     */
+    private static final boolean REVERSE;
+    static {
+        // to generate a reasonably random and well-mixed SALT, use an arbitrary
+        // value (a slice of pi), multiply with a random seed, then pick
+        // the mid 32-bits from the product. By picking a SALT value in the
+        // [0 ... 0xFFFF_FFFFL == 2^32-1] range, we ensure that for any positive
+        // int N, (SALT32L * N) >> 32 is a number in the [0 ... N-1] range. This
+        // property will be used to avoid more expensive modulo-based
+        // calculations.
+        long color = 0x243F_6A88_85A3_08D3L; // slice of pi
+
+        // BEGIN Android-changed: set seed directly, as CDS is not available.
+        // When running with -Xshare:dump, the VM will supply a "random" seed that's
+        // derived from the JVM build/version, so can we generate the exact same
+        // CDS archive for the same JDK build. This makes it possible to verify the
+        // consistency of the JDK build.
+        // long seed = CDS.getRandomSeedForDumping();
+        // if (seed == 0) {
+        //   seed = System.nanoTime();
+        // }
+        long seed = System.nanoTime();
+        // END Android-changed: set seed directly, as CDS is not available.
+        SALT32L = (int)((color * seed) >> 16) & 0xFFFF_FFFFL;
+        // use the lowest bit to determine if we should reverse iteration
+        REVERSE = (SALT32L & 1) == 0;
+    }
+
+    // BEGIN Android-changed: always initialize empty collections.
+    /*
+     * Constants following this might be initialized from the CDS archive via
+     * this array.
+     *
+    // private static Object[] archivedObjects;
+     */
+
+    private static final Object EMPTY = new Object();
+    static final ListN<?> EMPTY_LIST = new ListN<>(new Object[0], false);
+    static final ListN<?> EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
+    static final SetN<?> EMPTY_SET = new SetN<>();
+    static final MapN<?,?> EMPTY_MAP = new MapN<>();
+
+    /*
+    static {
+        CDS.initializeFromArchive(ImmutableCollections.class);
+        if (archivedObjects == null) {
+            EMPTY = new Object();
+            EMPTY_LIST = new ListN<>(new Object[0], false);
+            EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
+            EMPTY_SET = new SetN<>();
+            EMPTY_MAP = new MapN<>();
+            archivedObjects =
+                new Object[] { EMPTY, EMPTY_LIST, EMPTY_LIST_NULLS, EMPTY_SET, EMPTY_MAP };
+        } else {
+            EMPTY = archivedObjects[0];
+            EMPTY_LIST = (ListN)archivedObjects[1];
+            EMPTY_LIST_NULLS = (ListN)archivedObjects[2];
+            EMPTY_SET = (SetN)archivedObjects[3];
+            EMPTY_MAP = (MapN)archivedObjects[4];
+        }
+    }
+    */
+    // END Android-changed: always initialize empty collections.
+
+    static class Access {
+        static {
+            SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
+                public <E> List<E> listFromTrustedArray(Object[] array) {
+                    return ImmutableCollections.listFromTrustedArray(array);
+                }
+                public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) {
+                    return ImmutableCollections.listFromTrustedArrayNullsAllowed(array);
+                }
+            });
+        }
+    }
+
+    /** No instances. */
+    private ImmutableCollections() { }
+
+    /**
+     * The reciprocal of load factor. Given a number of elements
+     * to store, multiply by this factor to get the table size.
+     */
+    static final int EXPAND_FACTOR = 2;
+
+    static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+    @jdk.internal.ValueBased
+    static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
+        // all mutating methods throw UnsupportedOperationException
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+    }
+
+    // ---------- List Static Factory Methods ----------
+
+    /**
+     * Copies a collection into a new List, unless the arg is already a safe,
+     * null-prohibiting unmodifiable list, in which case the arg itself is returned.
+     * Null argument or null elements in the argument will result in NPE.
+     *
+     * @param <E> the List's element type
+     * @param input the input array
+     * @return the new list
+     */
+    @SuppressWarnings("unchecked")
+    static <E> List<E> listCopy(Collection<? extends E> coll) {
+        if (coll instanceof List12 || (coll instanceof ListN && ! ((ListN<?>)coll).allowNulls)) {
+            return (List<E>)coll;
+        } else {
+            return (List<E>)List.of(coll.toArray()); // implicit nullcheck of coll
+        }
+    }
+
+    /**
+     * Creates a new List from an untrusted array, creating a new array for internal
+     * storage, and checking for and rejecting null elements.
+     *
+     * @param <E> the List's element type
+     * @param input the input array
+     * @return the new list
+     */
+    @SafeVarargs
+    static <E> List<E> listFromArray(E... input) {
+        // copy and check manually to avoid TOCTOU
+        @SuppressWarnings("unchecked")
+        E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+        for (int i = 0; i < input.length; i++) {
+            tmp[i] = Objects.requireNonNull(input[i]);
+        }
+        return new ListN<>(tmp, false);
+    }
+
+    /**
+     * Creates a new List from a trusted array, checking for and rejecting null
+     * elements.
+     *
+     * <p>A trusted array has no references retained by the caller. It can therefore be
+     * safely reused as the List's internal storage, avoiding a defensive copy. The array's
+     * class must be Object[].class. This method is declared with a parameter type of
+     * Object... instead of E... so that a varargs call doesn't accidentally create an array
+     * of some class other than Object[].class.
+     *
+     * @param <E> the List's element type
+     * @param input the input array
+     * @return the new list
+     */
+    @SuppressWarnings("unchecked")
+    static <E> List<E> listFromTrustedArray(Object... input) {
+        assert input.getClass() == Object[].class;
+        for (Object o : input) { // implicit null check of 'input' array
+            Objects.requireNonNull(o);
+        }
+
+        return switch (input.length) {
+            case 0  -> (List<E>) ImmutableCollections.EMPTY_LIST;
+            case 1  -> (List<E>) new List12<>(input[0]);
+            case 2  -> (List<E>) new List12<>(input[0], input[1]);
+            default -> (List<E>) new ListN<>(input, false);
+        };
+    }
+
+    /**
+     * Creates a new List from a trusted array, allowing null elements.
+     *
+     * <p>A trusted array has no references retained by the caller. It can therefore be
+     * safely reused as the List's internal storage, avoiding a defensive copy. The array's
+     * class must be Object[].class. This method is declared with a parameter type of
+     * Object... instead of E... so that a varargs call doesn't accidentally create an array
+     * of some class other than Object[].class.
+     *
+     * <p>Avoids creating a List12 instance, as it cannot accommodate null elements.
+     *
+     * @param <E> the List's element type
+     * @param input the input array
+     * @return the new list
+     */
+    @SuppressWarnings("unchecked")
+    static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) {
+        assert input.getClass() == Object[].class;
+        if (input.length == 0) {
+            return (List<E>) EMPTY_LIST_NULLS;
+        } else {
+            return new ListN<>((E[])input, true);
+        }
+    }
+
+    // ---------- List Implementations ----------
+
+    @jdk.internal.ValueBased
+    static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
+            implements List<E>, RandomAccess {
+
+        // all mutating methods throw UnsupportedOperationException
+        @Override public void    add(int index, E element) { throw uoe(); }
+        @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
+        @Override public E       remove(int index) { throw uoe(); }
+        @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
+        @Override public E       set(int index, E element) { throw uoe(); }
+        @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
+
+        @Override
+        public List<E> subList(int fromIndex, int toIndex) {
+            int size = size();
+            subListRangeCheck(fromIndex, toIndex, size);
+            return SubList.fromList(this, fromIndex, toIndex);
+        }
+
+        static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+            if (fromIndex < 0)
+                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+            if (toIndex > size)
+                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+            if (fromIndex > toIndex)
+                throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                        ") > toIndex(" + toIndex + ")");
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new ListItr<E>(this, size());
+        }
+
+        @Override
+        public ListIterator<E> listIterator() {
+            return listIterator(0);
+        }
+
+        @Override
+        public ListIterator<E> listIterator(final int index) {
+            int size = size();
+            if (index < 0 || index > size) {
+                throw outOfBounds(index);
+            }
+            return new ListItr<E>(this, size, index);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+
+            if (!(o instanceof List)) {
+                return false;
+            }
+
+            Iterator<?> oit = ((List<?>) o).iterator();
+            for (int i = 0, s = size(); i < s; i++) {
+                if (!oit.hasNext() || !Objects.equals(get(i), oit.next())) {
+                    return false;
+                }
+            }
+            return !oit.hasNext();
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            for (int i = 0, s = size(); i < s; i++) {
+                hash = 31 * hash + Objects.hashCode(get(i));
+            }
+            return hash;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        IndexOutOfBoundsException outOfBounds(int index) {
+            return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
+        }
+    }
+
+    static final class ListItr<E> implements ListIterator<E> {
+
+        @Stable
+        private final List<E> list;
+
+        @Stable
+        private final int size;
+
+        @Stable
+        private final boolean isListIterator;
+
+        private int cursor;
+
+        ListItr(List<E> list, int size) {
+            this.list = list;
+            this.size = size;
+            this.cursor = 0;
+            isListIterator = false;
+        }
+
+        ListItr(List<E> list, int size, int index) {
+            this.list = list;
+            this.size = size;
+            this.cursor = index;
+            isListIterator = true;
+        }
+
+        public boolean hasNext() {
+            return cursor != size;
+        }
+
+        public E next() {
+            try {
+                int i = cursor;
+                E next = list.get(i);
+                cursor = i + 1;
+                return next;
+            } catch (IndexOutOfBoundsException e) {
+                throw new NoSuchElementException();
+            }
+        }
+
+        public void remove() {
+            throw uoe();
+        }
+
+        public boolean hasPrevious() {
+            if (!isListIterator) {
+                throw uoe();
+            }
+            return cursor != 0;
+        }
+
+        public E previous() {
+            if (!isListIterator) {
+                throw uoe();
+            }
+            try {
+                int i = cursor - 1;
+                E previous = list.get(i);
+                cursor = i;
+                return previous;
+            } catch (IndexOutOfBoundsException e) {
+                throw new NoSuchElementException();
+            }
+        }
+
+        public int nextIndex() {
+            if (!isListIterator) {
+                throw uoe();
+            }
+            return cursor;
+        }
+
+        public int previousIndex() {
+            if (!isListIterator) {
+                throw uoe();
+            }
+            return cursor - 1;
+        }
+
+        public void set(E e) {
+            throw uoe();
+        }
+
+        public void add(E e) {
+            throw uoe();
+        }
+    }
+
+    static final class SubList<E> extends AbstractImmutableList<E>
+            implements RandomAccess {
+
+        @Stable
+        private final AbstractImmutableList<E> root;
+
+        @Stable
+        private final int offset;
+
+        @Stable
+        private final int size;
+
+        private SubList(AbstractImmutableList<E> root, int offset, int size) {
+            assert root instanceof List12 || root instanceof ListN;
+            this.root = root;
+            this.offset = offset;
+            this.size = size;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) {
+            return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex);
+        }
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractImmutableList, which is
+         * not a SubList itself.
+         */
+        static <E> SubList<E> fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex) {
+            return new SubList<>(list, fromIndex, toIndex - fromIndex);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            return size;
+        }
+
+        public Iterator<E> iterator() {
+            return new ListItr<>(this, size());
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            rangeCheck(index);
+            return new ListItr<>(this, size(), index);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return SubList.fromSubList(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheck(int index) {
+            if (index < 0 || index > size) {
+                throw outOfBounds(index);
+            }
+        }
+
+        private boolean allowNulls() {
+            return root instanceof ListN && ((ListN<?>)root).allowNulls;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            if (!allowNulls() && o == null) {
+                throw new NullPointerException();
+            }
+            for (int i = 0, s = size(); i < s; i++) {
+                if (Objects.equals(o, get(i))) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        @Override
+        public int lastIndexOf(Object o) {
+            if (!allowNulls() && o == null) {
+                throw new NullPointerException();
+            }
+            for (int i = size() - 1; i >= 0; i--) {
+                if (Objects.equals(o, get(i))) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        @Override
+        public Object[] toArray() {
+            Object[] array = new Object[size];
+            for (int i = 0; i < size; i++) {
+                array[i] = get(i);
+            }
+            return array;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            T[] array = a.length >= size ? a :
+                    (T[])java.lang.reflect.Array
+                            .newInstance(a.getClass().getComponentType(), size);
+            for (int i = 0; i < size; i++) {
+                array[i] = (T)get(i);
+            }
+            if (array.length > size) {
+                array[size] = null; // null-terminate
+            }
+            return array;
+        }
+    }
+
+    @jdk.internal.ValueBased
+    static final class List12<E> extends AbstractImmutableList<E>
+            implements Serializable {
+
+        @Stable
+        private final E e0;
+
+        @Stable
+        private final Object e1;
+
+        List12(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+            // Use EMPTY as a sentinel for an unused element: not using null
+            // enables constant folding optimizations over single-element lists
+            this.e1 = EMPTY;
+        }
+
+        List12(E e0, E e1) {
+            this.e0 = Objects.requireNonNull(e0);
+            this.e1 = Objects.requireNonNull(e1);
+        }
+
+        @Override
+        public int size() {
+            return e1 != EMPTY ? 2 : 1;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public E get(int index) {
+            if (index == 0) {
+                return e0;
+            } else if (index == 1 && e1 != EMPTY) {
+                return (E)e1;
+            }
+            throw outOfBounds(index);
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            Objects.requireNonNull(o);
+            if (o.equals(e0)) {
+                return 0;
+            } else if (e1 != EMPTY && o.equals(e1)) {
+                return 1;
+            } else {
+                return -1;
+            }
+        }
+
+        @Override
+        public int lastIndexOf(Object o) {
+            Objects.requireNonNull(o);
+            if (e1 != EMPTY && o.equals(e1)) {
+                return 1;
+            } else if (o.equals(e0)) {
+                return 0;
+            } else {
+                return -1;
+            }
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            if (e1 == EMPTY) {
+                return new CollSer(CollSer.IMM_LIST, e0);
+            } else {
+                return new CollSer(CollSer.IMM_LIST, e0, e1);
+            }
+        }
+
+        @Override
+        public Object[] toArray() {
+            if (e1 == EMPTY) {
+                return new Object[] { e0 };
+            } else {
+                return new Object[] { e0, e1 };
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            T[] array = a.length >= size ? a :
+                    (T[])Array.newInstance(a.getClass().getComponentType(), size);
+            array[0] = (T)e0;
+            if (size == 2) {
+                array[1] = (T)e1;
+            }
+            if (array.length > size) {
+                array[size] = null; // null-terminate
+            }
+            return array;
+        }
+    }
+
+    @jdk.internal.ValueBased
+    static final class ListN<E> extends AbstractImmutableList<E>
+            implements Serializable {
+
+        @Stable
+        private final E[] elements;
+
+        @Stable
+        private final boolean allowNulls;
+
+        // caller must ensure that elements has no nulls if allowNulls is false
+        private ListN(E[] elements, boolean allowNulls) {
+            this.elements = elements;
+            this.allowNulls = allowNulls;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return elements.length == 0;
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+
+        @Override
+        public E get(int index) {
+            return elements[index];
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            return new CollSer(allowNulls ? CollSer.IMM_LIST_NULLS : CollSer.IMM_LIST, elements);
+        }
+
+        @Override
+        public Object[] toArray() {
+            return Arrays.copyOf(elements, elements.length);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = elements.length;
+            if (a.length < size) {
+                // Make a new array of a's runtime type, but my contents:
+                return (T[]) Arrays.copyOf(elements, size, a.getClass());
+            }
+            System.arraycopy(elements, 0, a, 0, size);
+            if (a.length > size) {
+                a[size] = null; // null-terminate
+            }
+            return a;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            if (!allowNulls && o == null) {
+                throw new NullPointerException();
+            }
+            Object[] es = elements;
+            for (int i = 0; i < es.length; i++) {
+                if (Objects.equals(o, es[i])) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        @Override
+        public int lastIndexOf(Object o) {
+            if (!allowNulls && o == null) {
+                throw new NullPointerException();
+            }
+            Object[] es = elements;
+            for (int i = es.length - 1; i >= 0; i--) {
+                if (Objects.equals(o, es[i])) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    // ---------- Set Implementations ----------
+
+    @jdk.internal.ValueBased
+    static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
+            implements Set<E> {
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            } else if (!(o instanceof Set)) {
+                return false;
+            }
+
+            Collection<?> c = (Collection<?>) o;
+            if (c.size() != size()) {
+                return false;
+            }
+            for (Object e : c) {
+                if (e == null || !contains(e)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public abstract int hashCode();
+    }
+
+    @jdk.internal.ValueBased
+    static final class Set12<E> extends AbstractImmutableSet<E>
+            implements Serializable {
+
+        @Stable
+        private final E e0;
+
+        @Stable
+        private final Object e1;
+
+        Set12(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+            // Use EMPTY as a sentinel for an unused element: not using null
+            // enable constant folding optimizations over single-element sets
+            this.e1 = EMPTY;
+        }
+
+        Set12(E e0, E e1) {
+            if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
+                throw new IllegalArgumentException("duplicate element: " + e0);
+            }
+
+            this.e0 = e0;
+            this.e1 = e1;
+        }
+
+        @Override
+        public int size() {
+            return (e1 == EMPTY) ? 1 : 2;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || e1.equals(o); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode() + (e1 == EMPTY ? 0 : e1.hashCode());
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<>() {
+                private int idx = (e1 == EMPTY) ? 1 : 2;
+
+                @Override
+                public boolean hasNext() {
+                    return idx > 0;
+                }
+
+                @Override
+                @SuppressWarnings("unchecked")
+                public E next() {
+                    if (idx == 1) {
+                        idx = 0;
+                        return (REVERSE || e1 == EMPTY) ? e0 : (E)e1;
+                    } else if (idx == 2) {
+                        idx = 1;
+                        return REVERSE ? (E)e1 : e0;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            if (e1 == EMPTY) {
+                return new CollSer(CollSer.IMM_SET, e0);
+            } else {
+                return new CollSer(CollSer.IMM_SET, e0, e1);
+            }
+        }
+
+        @Override
+        public Object[] toArray() {
+            if (e1 == EMPTY) {
+                return new Object[] { e0 };
+            } else if (REVERSE) {
+                return new Object[] { e1, e0 };
+            } else {
+                return new Object[] { e0, e1 };
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            T[] array = a.length >= size ? a :
+                    (T[])Array.newInstance(a.getClass().getComponentType(), size);
+            if (size == 1) {
+                array[0] = (T)e0;
+            } else if (REVERSE) {
+                array[0] = (T)e1;
+                array[1] = (T)e0;
+            } else {
+                array[0] = (T)e0;
+                array[1] = (T)e1;
+            }
+            if (array.length > size) {
+                array[size] = null; // null-terminate
+            }
+            return array;
+        }
+    }
+
+
+    /**
+     * An array-based Set implementation. The element array must be strictly
+     * larger than the size (the number of contained elements) so that at
+     * least one null is always present.
+     * @param <E> the element type
+     */
+    @jdk.internal.ValueBased
+    static final class SetN<E> extends AbstractImmutableSet<E>
+            implements Serializable {
+
+        @Stable
+        final E[] elements;
+
+        @Stable
+        final int size;
+
+        @SafeVarargs
+        @SuppressWarnings("unchecked")
+        SetN(E... input) {
+            size = input.length; // implicit nullcheck of input
+
+            elements = (E[])new Object[EXPAND_FACTOR * input.length];
+            for (int i = 0; i < input.length; i++) {
+                E e = input[i];
+                int idx = probe(e); // implicit nullcheck of e
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate element: " + e);
+                } else {
+                    elements[-(idx + 1)] = e;
+                }
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return size == 0;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return size > 0 && probe(o) >= 0;
+        }
+
+        private final class SetNIterator implements Iterator<E> {
+
+            private int remaining;
+
+            private int idx;
+
+            SetNIterator() {
+                remaining = size;
+                // pick a starting index in the [0 .. element.length-1] range
+                // randomly based on SALT32L
+                idx = (int) ((SALT32L * elements.length) >>> 32);
+            }
+
+            @Override
+            public boolean hasNext() {
+                return remaining > 0;
+            }
+
+            @Override
+            public E next() {
+                if (remaining > 0) {
+                    E element;
+                    int idx = this.idx;
+                    int len = elements.length;
+                    // step to the next element; skip null elements
+                    do {
+                        if (REVERSE) {
+                            if (++idx >= len) {
+                                idx = 0;
+                            }
+                        } else {
+                            if (--idx < 0) {
+                                idx = len - 1;
+                            }
+                        }
+                    } while ((element = elements[idx]) == null);
+                    this.idx = idx;
+                    remaining--;
+                    return element;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new SetNIterator();
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 0;
+            for (E e : elements) {
+                if (e != null) {
+                    h += e.hashCode();
+                }
+            }
+            return h;
+        }
+
+        // returns index at which element is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pe
+        private int probe(Object pe) {
+            int idx = Math.floorMod(pe.hashCode(), elements.length);
+            while (true) {
+                E ee = elements[idx];
+                if (ee == null) {
+                    return -idx - 1;
+                } else if (pe.equals(ee)) {
+                    return idx;
+                } else if (++idx == elements.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            Object[] array = new Object[size];
+            int dest = 0;
+            for (Object o : elements) {
+                if (o != null) {
+                    array[dest++] = o;
+                }
+            }
+            return new CollSer(CollSer.IMM_SET, array);
+        }
+
+        @Override
+        public Object[] toArray() {
+            Object[] array = new Object[size];
+            Iterator<E> it = iterator();
+            for (int i = 0; i < size; i++) {
+                array[i] = it.next();
+            }
+            return array;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            T[] array = a.length >= size ? a :
+                    (T[])Array.newInstance(a.getClass().getComponentType(), size);
+            Iterator<E> it = iterator();
+            for (int i = 0; i < size; i++) {
+                array[i] = (T)it.next();
+            }
+            if (array.length > size) {
+                array[size] = null; // null-terminate
+            }
+            return array;
+        }
+    }
+
+    // ---------- Map Implementations ----------
+
+    @jdk.internal.ValueBased
+    abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
+        @Override public void clear() { throw uoe(); }
+        @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
+        @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V put(K key, V value) { throw uoe(); }
+        @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
+        @Override public V putIfAbsent(K key, V value) { throw uoe(); }
+        @Override public V remove(Object key) { throw uoe(); }
+        @Override public boolean remove(Object key, Object value) { throw uoe(); }
+        @Override public V replace(K key, V value) { throw uoe(); }
+        @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
+        @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+
+        /**
+         * @implNote {@code null} values are disallowed in these immutable maps,
+         * so we can improve upon the default implementation since a
+         * {@code null} return from {@code get(key)} always means the default
+         * value should be returned.
+         */
+        @Override
+        public V getOrDefault(Object key, V defaultValue) {
+            V v;
+            return ((v = get(key)) != null)
+                    ? v
+                    : defaultValue;
+        }
+    }
+
+    @jdk.internal.ValueBased
+    static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        private final K k0;
+        @Stable
+        private final V v0;
+
+        Map1(K k0, V v0) {
+            this.k0 = Objects.requireNonNull(k0);
+            this.v0 = Objects.requireNonNull(v0);
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of(new KeyValueHolder<>(k0, v0));
+        }
+
+        @Override
+        public V get(Object o) {
+            return o.equals(k0) ? v0 : null; // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return o.equals(k0); // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            return o.equals(v0); // implicit nullcheck of o
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP, k0, v0);
+        }
+
+        @Override
+        public int hashCode() {
+            return k0.hashCode() ^ v0.hashCode();
+        }
+    }
+
+    /**
+     * An array-based Map implementation. There is a single array "table" that
+     * contains keys and values interleaved: table[0] is kA, table[1] is vA,
+     * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
+     * also be strictly larger than the size (the number of key-value pairs contained
+     * in the map) so that at least one null key is always present.
+     * @param <K> the key type
+     * @param <V> the value type
+     */
+    @jdk.internal.ValueBased
+    static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
+
+        @Stable
+        final Object[] table; // pairs of key, value
+
+        @Stable
+        final int size; // number of pairs
+
+        MapN(Object... input) {
+            if ((input.length & 1) != 0) { // implicit nullcheck of input
+                throw new InternalError("length is odd");
+            }
+            size = input.length >> 1;
+
+            int len = EXPAND_FACTOR * input.length;
+            len = (len + 1) & ~1; // ensure table is even length
+            table = new Object[len];
+
+            for (int i = 0; i < input.length; i += 2) {
+                @SuppressWarnings("unchecked")
+                    K k = Objects.requireNonNull((K)input[i]);
+                @SuppressWarnings("unchecked")
+                    V v = Objects.requireNonNull((V)input[i+1]);
+                int idx = probe(k);
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate key: " + k);
+                } else {
+                    int dest = -(idx + 1);
+                    table[dest] = k;
+                    table[dest+1] = v;
+                }
+            }
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            Objects.requireNonNull(o);
+            return size > 0 && probe(o) >= 0;
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            Objects.requireNonNull(o);
+            for (int i = 1; i < table.length; i += 2) {
+                Object v = table[i];
+                if (v != null && o.equals(v)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 0;
+            for (int i = 0; i < table.length; i += 2) {
+                Object k = table[i];
+                if (k != null) {
+                    hash += k.hashCode() ^ table[i + 1].hashCode();
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public V get(Object o) {
+            if (size == 0) {
+                Objects.requireNonNull(o);
+                return null;
+            }
+            int i = probe(o);
+            if (i >= 0) {
+                return (V)table[i+1];
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return size == 0;
+        }
+
+        class MapNIterator implements Iterator<Map.Entry<K,V>> {
+
+            private int remaining;
+
+            private int idx;
+
+            MapNIterator() {
+                remaining = size;
+                // pick an even starting index in the [0 .. table.length-1]
+                // range randomly based on SALT32L
+                idx = (int) ((SALT32L * (table.length >> 1)) >>> 32) << 1;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return remaining > 0;
+            }
+
+            private int nextIndex() {
+                int idx = this.idx;
+                if (REVERSE) {
+                    if ((idx += 2) >= table.length) {
+                        idx = 0;
+                    }
+                } else {
+                    if ((idx -= 2) < 0) {
+                        idx = table.length - 2;
+                    }
+                }
+                return this.idx = idx;
+            }
+
+            @Override
+            public Map.Entry<K,V> next() {
+                if (remaining > 0) {
+                    int idx;
+                    while (table[idx = nextIndex()] == null) {}
+                    @SuppressWarnings("unchecked")
+                    Map.Entry<K,V> e =
+                            new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
+                    remaining--;
+                    return e;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return new AbstractSet<>() {
+                @Override
+                public int size() {
+                    return MapN.this.size;
+                }
+
+                @Override
+                public Iterator<Map.Entry<K,V>> iterator() {
+                    return new MapNIterator();
+                }
+
+                // Android-added: AbstractCollection#clear implementation is no-op when
+                // collection is empty. Overriding this method to make Map.of().clear()
+                // and Map.of().entrySet().clear() behaviour equal.
+                @Override
+                public void clear() {
+                    throw uoe();
+                }
+            };
+        }
+
+        // returns index at which the probe key is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pk.
+        private int probe(Object pk) {
+            int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1;
+            while (true) {
+                @SuppressWarnings("unchecked")
+                K ek = (K)table[idx];
+                if (ek == null) {
+                    return -idx - 1;
+                } else if (pk.equals(ek)) {
+                    return idx;
+                } else if ((idx += 2) == table.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        @java.io.Serial
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        @java.io.Serial
+        private Object writeReplace() {
+            Object[] array = new Object[2 * size];
+            int len = table.length;
+            int dest = 0;
+            for (int i = 0; i < len; i += 2) {
+                if (table[i] != null) {
+                    array[dest++] = table[i];
+                    array[dest++] = table[i+1];
+                }
+            }
+            return new CollSer(CollSer.IMM_MAP, array);
+        }
+    }
+}
+
+// ---------- Serialization Proxy ----------
+
+/**
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
+ */
+final class CollSer implements Serializable {
+    @java.io.Serial
+    private static final long serialVersionUID = 6309168927139932177L;
+
+    static final int IMM_LIST       = 1;
+    static final int IMM_SET        = 2;
+    static final int IMM_MAP        = 3;
+    static final int IMM_LIST_NULLS = 4;
+
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, 3 for
+     * an immutable {@code Map}, and 4 for an immutable
+     * {@code List} that allows null elements.
+     *
+     * Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
+
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
+        array = a;
+    }
+
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len);
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#unmodifiable">List</a>,
+     * <a href="Map.html#unmodifiable">Map</a>, or
+     * <a href="Set.html#unmodifiable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
+    @java.io.Serial
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            if (array == null) {
+                throw new InvalidObjectException("null array");
+            }
+
+            // use low order 8 bits to indicate "kind"
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
+                case IMM_LIST:
+                    return List.of(array);
+                case IMM_LIST_NULLS:
+                    return ImmutableCollections.listFromTrustedArrayNullsAllowed(
+                            Arrays.copyOf(array, array.length, Object[].class));
+                case IMM_SET:
+                    return Set.of(array);
+                case IMM_MAP:
+                    if (array.length == 0) {
+                        return ImmutableCollections.EMPTY_MAP;
+                    } else if (array.length == 2) {
+                        return new ImmutableCollections.Map1<>(array[0], array[1]);
+                    } else {
+                        return new ImmutableCollections.MapN<>(array);
+                    }
+                default:
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
+            }
+        } catch (NullPointerException|IllegalArgumentException ex) {
+            InvalidObjectException ioe = new InvalidObjectException("invalid object");
+            ioe.initCause(ex);
+            throw ioe;
+        }
+    }
+}
diff --git a/android-35/java/util/InputMismatchException.java b/android-35/java/util/InputMismatchException.java
new file mode 100644
index 0000000..522a553
--- /dev/null
+++ b/android-35/java/util/InputMismatchException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by a {@code Scanner} to indicate that the token
+ * retrieved does not match the pattern for the expected type, or
+ * that the token is out of range for the expected type.
+ *
+ * @see     java.util.Scanner
+ * @since   1.5
+ */
+public class InputMismatchException extends NoSuchElementException {
+    @java.io.Serial
+    private static final long serialVersionUID = 8811230760997066428L;
+
+    /**
+     * Constructs an {@code InputMismatchException} with {@code null}
+     * as its error message string.
+     */
+    public InputMismatchException() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code InputMismatchException}, saving a reference
+     * to the error message string {@code s} for later retrieval by the
+     * {@code getMessage} method.
+     *
+     * @param   s   the detail message.
+     */
+    public InputMismatchException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/IntSummaryStatistics.java b/android-35/java/util/IntSummaryStatistics.java
new file mode 100644
index 0000000..6c63351
--- /dev/null
+++ b/android-35/java/util/IntSummaryStatistics.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of ints with:
+ * <pre> {@code
+ * IntSummaryStatistics stats = intStream.collect(IntSummaryStatistics::new,
+ *                                                IntSummaryStatistics::accept,
+ *                                                IntSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code IntSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * IntSummaryStatistics stats = people.stream()
+ *                                    .collect(Collectors.summarizingInt(Person::getDependents));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their number of dependents.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingInt(java.util.function.ToIntFunction)
+ * Collectors.summarizingInt()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the count or the sum.
+ * @since 1.8
+ */
+public class IntSummaryStatistics implements IntConsumer {
+    private long count;
+    private long sum;
+    private int min = Integer.MAX_VALUE;
+    private int max = Integer.MIN_VALUE;
+
+    /**
+     * Constructs an empty instance with zero count, zero sum,
+     * {@code Integer.MAX_VALUE} min, {@code Integer.MIN_VALUE} max and zero
+     * average.
+     */
+    public IntSummaryStatistics() { }
+
+    /**
+     * Constructs a non-empty instance with the specified {@code count},
+     * {@code min}, {@code max}, and {@code sum}.
+     *
+     * <p>If {@code count} is zero then the remaining arguments are ignored and
+     * an empty instance is constructed.
+     *
+     * <p>If the arguments are inconsistent then an {@code IllegalArgumentException}
+     * is thrown.  The necessary consistent argument conditions are:
+     * <ul>
+     *   <li>{@code count >= 0}</li>
+     *   <li>{@code min <= max}</li>
+     * </ul>
+     * @apiNote
+     * The enforcement of argument correctness means that the retrieved set of
+     * recorded values obtained from a {@code IntSummaryStatistics} source
+     * instance may not be a legal set of arguments for this constructor due to
+     * arithmetic overflow of the source's recorded count of values.
+     * The consistent argument conditions are not sufficient to prevent the
+     * creation of an internally inconsistent instance.  An example of such a
+     * state would be an instance with: {@code count} = 2, {@code min} = 1,
+     * {@code max} = 2, and {@code sum} = 0.
+     *
+     * @param count the count of values
+     * @param min the minimum value
+     * @param max the maximum value
+     * @param sum the sum of all values
+     * @throws IllegalArgumentException if the arguments are inconsistent
+     * @since 10
+     */
+    public IntSummaryStatistics(long count, int min, int max, long sum)
+            throws IllegalArgumentException {
+        if (count < 0L) {
+            throw new IllegalArgumentException("Negative count value");
+        } else if (count > 0L) {
+            if (min > max) throw new IllegalArgumentException("Minimum greater than maximum");
+
+            this.count = count;
+            this.sum = sum;
+            this.min = min;
+            this.max = max;
+        }
+        // Use default field values if count == 0
+    }
+
+    /**
+     * Records a new value into the summary information
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code IntSummaryStatistics} into this one.
+     *
+     * @param other another {@code IntSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(IntSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Integer.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Integer.MAX_VALUE} if none
+     */
+    public final int getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Integer.MIN_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the maximum value, or {@code Integer.MIN_VALUE} if none
+     */
+    public final int getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    /**
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    @Override
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/android-35/java/util/InvalidPropertiesFormatException.java b/android-35/java/util/InvalidPropertiesFormatException.java
new file mode 100644
index 0000000..3b1801b
--- /dev/null
+++ b/android-35/java/util/InvalidPropertiesFormatException.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.NotSerializableException;
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of properties, as per the {@link Properties}
+ * specification.<p>
+ *
+ * Note, that although InvalidPropertiesFormatException inherits Serializable
+ * interface from Exception, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @see     Properties
+ * @since   1.5
+ * @serial exclude
+ */
+
+public class InvalidPropertiesFormatException extends IOException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 7763056076009360219L;
+
+    /**
+     * Constructs an InvalidPropertiesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPropertiesFormatException(Throwable cause) {
+        super(cause==null ? null : cause.toString());
+        this.initCause(cause);
+    }
+
+   /**
+    * Constructs an InvalidPropertiesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPropertiesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream out)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream in)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+}
diff --git a/android-35/java/util/Iterator.java b/android-35/java/util/Iterator.java
new file mode 100644
index 0000000..aaf6a04
--- /dev/null
+++ b/android-35/java/util/Iterator.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * An iterator over a collection.  {@code Iterator} takes the place of
+ * {@link Enumeration} in the Java Collections Framework.  Iterators
+ * differ from enumerations in two ways:
+ *
+ * <ul>
+ *      <li> Iterators allow the caller to remove elements from the
+ *           underlying collection during the iteration with well-defined
+ *           semantics.
+ *      <li> Method names have been improved.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @apiNote
+ * An {@link Enumeration} can be converted into an {@code Iterator} by
+ * using the {@link Enumeration#asIterator} method.
+ *
+ * @param <E> the type of elements returned by this iterator
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see ListIterator
+ * @see Iterable
+ * @since 1.2
+ */
+public interface Iterator<E> {
+    /**
+     * Returns {@code true} if the iteration has more elements.
+     * (In other words, returns {@code true} if {@link #next} would
+     * return an element rather than throwing an exception.)
+     *
+     * @return {@code true} if the iteration has more elements
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the iteration.
+     *
+     * @return the next element in the iteration
+     * @throws NoSuchElementException if the iteration has no more elements
+     */
+    E next();
+
+    /**
+     * Removes from the underlying collection the last element returned
+     * by this iterator (optional operation).  This method can be called
+     * only once per call to {@link #next}.
+     * <p>
+     * The behavior of an iterator is unspecified if the underlying collection
+     * is modified while the iteration is in progress in any way other than by
+     * calling this method, unless an overriding class has specified a
+     * concurrent modification policy.
+     * <p>
+     * The behavior of an iterator is unspecified if this method is called
+     * after a call to the {@link #forEachRemaining forEachRemaining} method.
+     *
+     * @implSpec
+     * The default implementation throws an instance of
+     * {@link UnsupportedOperationException} and performs no other action.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this iterator
+     *
+     * @throws IllegalStateException if the {@code next} method has not
+     *         yet been called, or the {@code remove} method has already
+     *         been called after the last call to the {@code next}
+     *         method
+     */
+    default void remove() {
+        throw new UnsupportedOperationException("remove");
+    }
+
+    /**
+     * Performs the given action for each remaining element until all elements
+     * have been processed or the action throws an exception.  Actions are
+     * performed in the order of iteration, if that order is specified.
+     * Exceptions thrown by the action are relayed to the caller.
+     * <p>
+     * The behavior of an iterator is unspecified if the action modifies the
+     * collection in any way (even by calling the {@link #remove remove} method
+     * or other mutator methods of {@code Iterator} subtypes),
+     * unless an overriding class has specified a concurrent modification policy.
+     * <p>
+     * Subsequent behavior of an iterator is unspecified if the action throws an
+     * exception.
+     *
+     * @implSpec
+     * <p>The default implementation behaves as if:
+     * <pre>{@code
+     *     while (hasNext())
+     *         action.accept(next());
+     * }</pre>
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     * @since 1.8
+     */
+    default void forEachRemaining(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        while (hasNext())
+            action.accept(next());
+    }
+}
diff --git a/android-35/java/util/JapaneseImperialCalendar.java b/android-35/java/util/JapaneseImperialCalendar.java
new file mode 100644
index 0000000..423bd87
--- /dev/null
+++ b/android-35/java/util/JapaneseImperialCalendar.java
@@ -0,0 +1,2346 @@
+/*
+ * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import sun.util.locale.provider.CalendarDataUtility;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.LocalGregorianCalendar;
+
+/**
+ * {@code JapaneseImperialCalendar} implements a Japanese
+ * calendar system in which the imperial era-based year numbering is
+ * supported from the Meiji era. The following are the eras supported
+ * by this calendar system.
+ * <pre>{@code
+ * ERA value   Era name    Since (in Gregorian)
+ * ------------------------------------------------------
+ *     0       N/A         N/A
+ *     1       Meiji       1868-01-01T00:00:00 local time
+ *     2       Taisho      1912-07-30T00:00:00 local time
+ *     3       Showa       1926-12-25T00:00:00 local time
+ *     4       Heisei      1989-01-08T00:00:00 local time
+ *     5       Reiwa       2019-05-01T00:00:00 local time
+ * ------------------------------------------------------
+ * }</pre>
+ *
+ * <p>{@code ERA} value 0 specifies the years before Meiji and
+ * the Gregorian year values are used. Unlike
+ * {@link GregorianCalendar}, the Julian to Gregorian transition is not
+ * supported because it doesn't make any sense to the Japanese
+ * calendar systems used before Meiji. To represent the years before
+ * Gregorian year 1, 0 and negative values are used. The Japanese
+ * Imperial rescripts and government decrees don't specify how to deal
+ * with time differences for applying the era transitions. This
+ * calendar implementation assumes local time for all transitions.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.6
+ */
+class JapaneseImperialCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * This implementation uses
+     * sun.util.calendar.LocalGregorianCalendar to perform most of the
+     * calendar calculations.
+     */
+
+    /**
+     * The ERA constant designating the era before Meiji.
+     */
+    public static final int BEFORE_MEIJI = 0;
+
+    /**
+     * The ERA constant designating the Meiji era.
+     */
+    public static final int MEIJI = 1;
+
+    /**
+     * The ERA constant designating the Taisho era.
+     */
+    public static final int TAISHO = 2;
+
+    /**
+     * The ERA constant designating the Showa era.
+     */
+    public static final int SHOWA = 3;
+
+    /**
+     * The ERA constant designating the Heisei era.
+     */
+    public static final int HEISEI = 4;
+
+    // Android-changed: Call the New Era it's proper name Reiwa.
+    /**
+     * The ERA constant designating the Reiwa era.
+     */
+    public static final int REIWA = 5;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+
+    // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
+    private static final LocalGregorianCalendar jcal
+        = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
+
+    // Gregorian calendar instance. This is required because era
+    // transition dates are given in Gregorian dates.
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    // The Era instance representing "before Meiji".
+    private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
+
+    // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
+    // doesn't have an Era representing before Meiji, which is
+    // inconvenient for a Calendar. So, era[0] is a reference to
+    // BEFORE_MEIJI_ERA.
+    private static final Era[] eras;
+
+    // Fixed date of the first date of each era.
+    private static final long[] sinceFixedDates;
+
+    // The current era
+    private static final int currentEra;
+
+    /*
+     * <pre>
+     *                                 Greatest       Least
+     * Field name             Minimum   Minimum     Maximum     Maximum
+     * ----------             -------   -------     -------     -------
+     * ERA                          0         0           1           1
+     * YEAR                -292275055         1           ?           ?
+     * MONTH                        0         0          11          11
+     * WEEK_OF_YEAR                 1         1          52*         53
+     * WEEK_OF_MONTH                0         0           4*          6
+     * DAY_OF_MONTH                 1         1          28*         31
+     * DAY_OF_YEAR                  1         1         365*        366
+     * DAY_OF_WEEK                  1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH        -1        -1           4*          6
+     * AM_PM                        0         0           1           1
+     * HOUR                         0         0          11          11
+     * HOUR_OF_DAY                  0         0          23          23
+     * MINUTE                       0         0          59          59
+     * SECOND                       0         0          59          59
+     * MILLISECOND                  0         0         999         999
+     * ZONE_OFFSET             -13:00    -13:00       14:00       14:00
+     * DST_OFFSET                0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on eras
+     */
+    static final int MIN_VALUES[] = {
+        0,              // ERA
+        -292275055,     // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        0,              // ERA (initialized later)
+        0,              // YEAR (initialized later)
+        JANUARY,        // MONTH (Showa 64 ended in January.)
+        0,              // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.)
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        0,              // DAY_OF_YEAR (initialized later)
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        0,              // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.6
+    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
+    @java.io.Serial
+    private static final long serialVersionUID = -3364572813905467929L;
+
+    static {
+        Era[] es = jcal.getEras();
+        int length = es.length + 1;
+        eras = new Era[length];
+        sinceFixedDates = new long[length];
+
+        // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
+        // same as Gregorian.
+        int index = BEFORE_MEIJI;
+        // Android-removed: Zygote could initialize this class when system has outdated time.
+        // int current = index;
+        sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
+        eras[index++] = BEFORE_MEIJI_ERA;
+        for (Era e : es) {
+            // Android-removed: Zygote could initialize this class when system has outdated time.
+            // Android hard-code the current era. Unlike upstream, Android does not add the new era
+            // in the code until the new era arrives. Thus, Android can't have newer era than the
+            // real world. currentEra is the latest Era that Android knows about.
+            // if(e.getSince(TimeZone.NO_TIMEZONE) < System.currentTimeMillis()) {
+            //     current = index;
+            // }
+            CalendarDate d = e.getSinceDate();
+            sinceFixedDates[index] = gcal.getFixedDate(d);
+            eras[index++] = e;
+        }
+        // Android-changed: Zygote could initialize this class when system has outdated time.
+        // currentEra = current;
+        currentEra = REIWA;
+
+        LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
+
+        // Calculate the least maximum year and least day of Year
+        // values. The following code assumes that there's at most one
+        // era transition in a Gregorian year.
+        int year = Integer.MAX_VALUE;
+        int dayOfYear = Integer.MAX_VALUE;
+        CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        for (int i = 1; i < eras.length; i++) {
+            long fd = sinceFixedDates[i];
+            CalendarDate transitionDate = eras[i].getSinceDate();
+            date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
+            long fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fd - fdd) + 1, dayOfYear);
+            }
+            date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
+            fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fdd - fd) + 1, dayOfYear);
+            }
+            LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
+            int y = lgd.getYear();
+            // Unless the first year starts from January 1, the actual
+            // max value could be one year short. For example, if it's
+            // Showa 63 January 8, 63 is the actual max value since
+            // Showa 64 January 8 doesn't exist.
+            if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) {
+                y--;
+            }
+            year = Math.min(y, year);
+        }
+        LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value.
+        LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear;
+    }
+
+    /**
+     * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to
+     * avoid overhead of creating it for each calculation.
+     */
+    private transient LocalGregorianCalendar.Date jdate;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the daylight saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+    /**
+     * Constructs a {@code JapaneseImperialCalendar} based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs an "empty" {@code JapaneseImperialCalendar}.
+     *
+     * @param zone    the given time zone
+     * @param aLocale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale, boolean flag) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+    }
+
+    /**
+     * Returns {@code "japanese"} as the calendar type of this {@code
+     * JapaneseImperialCalendar}.
+     *
+     * @return {@code "japanese"}
+     */
+    @Override
+    public String getCalendarType() {
+        return "japanese";
+    }
+
+    /**
+     * Compares this {@code JapaneseImperialCalendar} to the specified
+     * {@code Object}. The result is {@code true} if and
+     * only if the argument is a {@code JapaneseImperialCalendar} object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * {@code Calendar} parameters.
+     *
+     * @param obj the object to compare with.
+     * @return {@code true} if this object is equal to {@code obj};
+     * {@code false} otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof JapaneseImperialCalendar &&
+            super.equals(obj);
+    }
+
+    /**
+     * Generates the hash code for this
+     * {@code JapaneseImperialCalendar} object.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ jdate.hashCode();
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of {@code field}
+     * after the call minus the value of {@code field} before the
+     * call is {@code amount}, modulo any overflow that has occurred in
+     * {@code field}. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * {@code field} is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. {@code HOUR} is a smaller field than
+     * {@code DAY_OF_MONTH}. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @throws    IllegalArgumentException if {@code field} is
+     * {@code ZONE_OFFSET}, {@code DST_OFFSET}, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    @Override
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addYear(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == MONTH) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addMonth(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            } else if (era > eras.length - 1) {
+                era = eras.length - 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to milliseconds
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to milliseconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = cachedFixedDate;
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
+            zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            // If the time zone offset has changed, then adjust the difference.
+            if (zoneOffset != 0) {
+                setTimeInMillis(time + zoneOffset);
+                long fd2 = cachedFixedDate;
+                // If the adjustment has changed the date, then take
+                // the previous one.
+                if (fd2 != fd) {
+                    setTimeInMillis(time - zoneOffset);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to {@code field}.
+     * @throws    IllegalArgumentException if {@code field} is
+     * {@code ZONE_OFFSET}, {@code DST_OFFSET}, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    @Override
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case ERA:
+        case AM_PM:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed
+            // minima and maxima. Other fields are complicated, since
+            // the range within they must roll varies depending on the
+            // date, a time zone and the era transitions.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int unit = max + 1; // 12 or 24 hours
+                int h = internalGet(field);
+                int nh = (h + amount) % unit;
+                if (nh < 0) {
+                    nh += unit;
+                }
+                time += ONE_HOUR * (nh - h);
+
+                // The day might have changed, which could happen if
+                // the daylight saving time transition brings it to
+                // the next day, although it's very unlikely. But we
+                // have to make sure not to change the larger fields.
+                CalendarDate d = jcal.getCalendarDate(time, getZone());
+                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
+                    d.setEra(jdate.getEra());
+                    d.setDate(internalGet(YEAR),
+                              internalGet(MONTH) + 1,
+                              internalGet(DAY_OF_MONTH));
+                    if (field == HOUR) {
+                        assert (internalGet(AM_PM) == PM);
+                        d.addHours(+12); // restore PM
+                    }
+                    time = jcal.getTime(d);
+                }
+                int hourOfDay = d.getHours();
+                internalSet(field, hourOfDay % unit);
+                if (field == HOUR) {
+                    internalSet(HOUR_OF_DAY, hourOfDay);
+                } else {
+                    internalSet(AM_PM, hourOfDay / 12);
+                    internalSet(HOUR, hourOfDay % 12);
+                }
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case YEAR:
+            min = getActualMinimum(field);
+            max = getActualMaximum(field);
+            break;
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                        max = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == max) {
+                            // To avoid overflow, use an equivalent year.
+                            jd.addYear(-400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() > d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() > d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() - 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else if (year == getMinimum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        min = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == min) {
+                            // To avoid underflow, use an equivalent year.
+                            jd.addYear(+400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() < d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() + 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else {
+                        int mon = (internalGet(MONTH) + amount) % 12;
+                        if (mon < 0) {
+                            mon += 12;
+                        }
+                        set(MONTH, mon);
+
+                        // Keep the day of month in the range.  We
+                        // don't want to spill over into the next
+                        // month; e.g., we don't want jan31 + 1 mo ->
+                        // feb31 -> mar3.
+                        int monthLen = monthLength(mon);
+                        if (internalGet(DAY_OF_MONTH) > monthLen) {
+                            set(DAY_OF_MONTH, monthLen);
+                        }
+                    }
+                } else {
+                    int eraIndex = getEraIndex(jdate);
+                    CalendarDate transition = null;
+                    if (jdate.getYear() == 1) {
+                        transition = eras[eraIndex].getSinceDate();
+                        min = transition.getMonth() - 1;
+                    } else {
+                        if (eraIndex < eras.length - 1) {
+                            transition = eras[eraIndex + 1].getSinceDate();
+                            if (transition.getYear() == jdate.getNormalizedYear()) {
+                                max = transition.getMonth() - 1;
+                                if (transition.getDayOfMonth() == 1) {
+                                    max--;
+                                }
+                            }
+                        }
+                    }
+
+                    if (min == max) {
+                        // The year has only one month. No need to
+                        // process further. (Showa Gan-nen (year 1)
+                        // and the last year have only one month.)
+                        return;
+                    }
+                    int n = getRolledValue(internalGet(field), amount, min, max);
+                    set(MONTH, n);
+                    if (n == min) {
+                        if (!(transition.getMonth() == BaseCalendar.JANUARY
+                              && transition.getDayOfMonth() == 1)) {
+                            if (jdate.getDayOfMonth() < transition.getDayOfMonth()) {
+                                set(DAY_OF_MONTH, transition.getDayOfMonth());
+                            }
+                        }
+                    } else if (n == max && (transition.getMonth() - 1 == n)) {
+                        int dom = transition.getDayOfMonth();
+                        if (jdate.getDayOfMonth() >= dom) {
+                            set(DAY_OF_MONTH, dom - 1);
+                        }
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = jdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                    } else if (year == getMinimum(YEAR)) {
+                        min = getActualMinimum(WEEK_OF_YEAR);
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+
+                    }
+                    // If the new value is in between min and max
+                    // (exclusive), then we can use the value.
+                    if (value > min && value < max) {
+                        set(WEEK_OF_YEAR, value);
+                        return;
+                    }
+                    long fd = cachedFixedDate;
+                    // Make sure that the min week has the current DAY_OF_WEEK
+                    long day1 = fd - (7 * (woy - min));
+                    if (year != getMinimum(YEAR)) {
+                        if (gcal.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+                    } else {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        if (day1 < jcal.getFixedDate(d)) {
+                            min++;
+                        }
+                    }
+
+                    // Make sure the same thing for the max week
+                    fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                    if (gcal.getYearFromFixedDate(fd) != y) {
+                        max--;
+                    }
+                    break;
+                }
+
+                // Handle transition here.
+                long fd = cachedFixedDate;
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                LocalGregorianCalendar.Date d = getCalendarDate(day1);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                jcal.getCalendarDateFromFixedDate(d, fd);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isTransitionYear = isTransitionYear(jdate.getNormalizedYear());
+                // dow: relative day of week from the first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = cachedFixedDate;
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isTransitionYear) {
+                    month1 = getFixedDateMonth1(jdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = jcal.getMonthLength(jdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                                     getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                set(DAY_OF_MONTH, getCalendarDate(nfd).getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    max = jcal.getMonthLength(jdate);
+                    break;
+                }
+
+                // TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...
+
+                // Transition handling. We can't change year and era
+                // values here due to the Calendar roll spec!
+                long month1 = getFixedDateMonth1(jdate, cachedFixedDate);
+
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(cachedFixedDate - month1), amount,
+                                           0, actualMonthLength() - 1);
+                LocalGregorianCalendar.Date d = getCalendarDate(month1 + value);
+                assert getEraIndex(d) == internalGetEra()
+                    && d.getYear() == internalGet(YEAR) && d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle transition. We can't change year and era values
+                // here due to the Calendar roll spec.
+                int value = getRolledValue(internalGet(DAY_OF_YEAR), amount, min, max);
+                long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
+                LocalGregorianCalendar.Date d = getCalendarDate(jan0 + value);
+                assert getEraIndex(d) == internalGetEra() && d.getYear() == internalGet(YEAR);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                int normalizedYear = jdate.getNormalizedYear();
+                if (!isTransitionYear(normalizedYear) && !isTransitionYear(normalizedYear - 1)) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the transition year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = cachedFixedDate;
+                long dowFirst = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(ERA, getEraIndex(d));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after having normalized, min should be 1.
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = jcal.getMonthLength(jdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Transition year handling.
+                long fd = cachedFixedDate;
+                long month1 = getFixedDateMonth1(jdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    @Override
+    public String getDisplayName(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        int fieldValue = get(field);
+
+        // "GanNen" is supported only in the LONG style.
+        if (field == YEAR
+            && (getBaseStyle(style) != LONG || fieldValue != 1 || get(ERA) == 0)) {
+            return null;
+        }
+
+        String name = CalendarDataUtility.retrieveFieldValueName(getCalendarType(), field,
+                                                                 fieldValue, style, locale);
+        // If the ERA value is null or empty, then
+        // try to get its name or abbreviation from the Era instance.
+        if ((name == null || name.isEmpty()) &&
+                field == ERA &&
+                fieldValue < eras.length) {
+            Era era = eras[fieldValue];
+            name = (style == SHORT) ? era.getAbbreviation() : era.getName();
+        }
+        return name;
+    }
+
+    @Override
+    public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        Map<String, Integer> names;
+        names = CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
+        // If strings[] has fewer than eras[], get more names from eras[].
+        if (names != null) {
+            if (field == ERA) {
+                int size = names.size();
+                if (style == ALL_STYLES) {
+                    Set<Integer> values = new HashSet<>();
+                    // count unique era values
+                    for (String key : names.keySet()) {
+                        values.add(names.get(key));
+                    }
+                    size = values.size();
+                }
+                if (size < eras.length) {
+                    int baseStyle = getBaseStyle(style);
+                    for (int i = 0; i < eras.length; i++) {
+                        if (!names.values().contains(i)) {
+                            Era era = eras[i];
+                            if (baseStyle == ALL_STYLES || baseStyle == SHORT
+                                    || baseStyle == NARROW_FORMAT) {
+                                names.put(era.getAbbreviation(), i);
+                            }
+                            if (baseStyle == ALL_STYLES || baseStyle == LONG) {
+                                names.put(era.getName(), i);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * {@code Calendar} instance. The minimum value is
+     * defined as the smallest value returned by the
+     * {@link Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * {@code GregorianCalendar} instance. The maximum value is
+     * defined as the largest value returned by the
+     * {@link Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMaximum(int field) {
+        return switch (field) {
+            case YEAR -> {
+                // The value should depend on the time zone of this calendar.
+                LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                yield Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
+            }
+            default -> MAX_VALUES[field];
+        };
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this {@code GregorianCalendar} instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getGreatestMinimum(int field) {
+        return field == YEAR ? 1 : MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this {@code GregorianCalendar} instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getLeastMaximum(int field) {
+        return switch (field) {
+            case YEAR -> Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
+            default -> LEAST_MAX_VALUES[field];
+        };
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this {@code JapaneseImperialCalendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getActualMinimum(int field) {
+        if (!isFieldSet(YEAR_MASK|MONTH_MASK|WEEK_OF_YEAR_MASK, field)) {
+            return getMinimum(field);
+        }
+
+        int value = 0;
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        // Get a local date which includes time of day and time zone,
+        // which are missing in jc.jdate.
+        LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc.getTimeInMillis(),
+                                                              getZone());
+        int eraIndex = getEraIndex(jd);
+        switch (field) {
+            case YEAR -> {
+                if (eraIndex > BEFORE_MEIJI) {
+                    value = 1;
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    // Use the same year in jd to take care of leap
+                    // years. i.e., both jd and d must agree on leap
+                    // or common years.
+                    jd.setYear(d.getYear());
+                    jcal.normalize(jd);
+                    assert jd.isLeapYear() == d.isLeapYear();
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                } else {
+                    value = getMinimum(field);
+                    CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    // Use an equvalent year of d.getYear() if
+                    // possible. Otherwise, ignore the leap year and
+                    // common year difference.
+                    int y = d.getYear();
+                    if (y > 400) {
+                        y -= 400;
+                    }
+                    jd.setYear(y);
+                    jcal.normalize(jd);
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                }
+            }
+            case MONTH -> {
+                // In Before Meiji and Meiji, January is the first month.
+                if (eraIndex > MEIJI && jd.getYear() == 1) {
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    value = d.getMonth() - 1;
+                    if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                        value++;
+                    }
+                }
+            }
+            case WEEK_OF_YEAR -> {
+                value = 1;
+                CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                // shift 400 years to avoid underflow
+                d.addYear(+400);
+                jcal.normalize(d);
+                jd.setEra(d.getEra());
+                jd.setYear(d.getYear());
+                jcal.normalize(jd);
+
+                long jan1 = jcal.getFixedDate(d);
+                long fd = jcal.getFixedDate(jd);
+                int woy = getWeekNumber(jan1, fd);
+                long day1 = fd - (7 * (woy - 1));
+                if ((day1 < jan1) ||
+                    (day1 == jan1 &&
+                     jd.getTimeOfDay() < d.getTimeOfDay())) {
+                    value++;
+                }
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is Heisei 16February 1,
+     * the actual maximum value of the {@code DAY_OF_MONTH} field
+     * is 29 because Heisei 16 is a leap year, and if the date of this
+     * instance is Heisei 17 February 1, it's 28.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this {@code JapaneseImperialCalendar}
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     */
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        LocalGregorianCalendar.Date date = jc.jdate;
+
+        return switch (field) {
+            case MONTH -> {
+                int month = DECEMBER;
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    if (fd < transition) {
+                        LocalGregorianCalendar.Date ldate
+                            = (LocalGregorianCalendar.Date) date.clone();
+                        jcal.getCalendarDateFromFixedDate(ldate, transition - 1);
+                        month = ldate.getMonth() - 1;
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                        month = d.getMonth() - 1;
+                    }
+                }
+                yield month;
+            }
+            case DAY_OF_MONTH -> jcal.getMonthLength(date);
+            case DAY_OF_YEAR -> {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // Handle transition year.
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                    if (fd < transition) {
+                        yield (int) (transition - gcal.getFixedDate(d));
+                    }
+                    d.addYear(1);
+                    yield (int) (gcal.getFixedDate(d) - transition);
+                }
+                LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                    long fd = jcal.getFixedDate(d);
+                    long jan1 = getFixedDateJan1(d, fd);
+                    yield (int) (fd - jan1) + 1;
+                } else if (date.getYear() == getMinimum(YEAR)) {
+                    CalendarDate d1 = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    long fd1 = jcal.getFixedDate(d1);
+                    d1.addYear(1);
+                    d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
+                    jcal.normalize(d1);
+                    long fd2 = jcal.getFixedDate(d1);
+                    yield (int) (fd2 - fd1);
+                } else {
+                    yield jcal.getYearLength(date);
+                }
+            }
+            case WEEK_OF_YEAR -> {
+                if (!isTransitionYear(date.getNormalizedYear())) {
+                    LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                    if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
+                        long fd = jcal.getFixedDate(jd);
+                        long jan1 = getFixedDateJan1(jd, fd);
+                        yield getWeekNumber(jan1, fd);
+                    } else if (date.getEra() == null && date.getYear() == getMinimum(YEAR)) {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        // shift 400 years to avoid underflow
+                        d.addYear(+400);
+                        jcal.normalize(d);
+                        jd.setEra(d.getEra());
+                        jd.setDate(d.getYear() + 1, BaseCalendar.JANUARY, 1);
+                        jcal.normalize(jd);
+                        long jan1 = jcal.getFixedDate(d);
+                        long nextJan1 = jcal.getFixedDate(jd);
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int) (nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek()) {
+                            nextJan1st -= 7;
+                        }
+                        yield getWeekNumber(jan1, nextJan1st);
+                    }
+                    // Get the day of week of January 1 of the year
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                    int dayOfWeek = gcal.getDayOfWeek(d);
+                    // Normalize the day of week with the firstDayOfWeek value
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                    if ((magic == 6) ||
+                        (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                        yield 53;
+                    }
+                    yield 52;
+                }
+
+                if (jc == this) {
+                    jc = (JapaneseImperialCalendar) jc.clone();
+                }
+                int max = getActualMaximum(DAY_OF_YEAR);
+                jc.set(DAY_OF_YEAR, max);
+                int weekOfYear = jc.get(WEEK_OF_YEAR);
+                if (weekOfYear == 1 && max > 7) {
+                    jc.add(WEEK_OF_YEAR, -1);
+                    weekOfYear = jc.get(WEEK_OF_YEAR);
+                }
+                yield weekOfYear;
+            }
+            case WEEK_OF_MONTH -> {
+                LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
+                    long fd = jcal.getFixedDate(jd);
+                    long month1 = fd - jd.getDayOfMonth() + 1;
+                    yield getWeekNumber(month1, fd);
+                }
+                CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
+                int dayOfWeek = gcal.getDayOfWeek(d);
+                int monthLength = actualMonthLength();
+                dayOfWeek -= getFirstDayOfWeek();
+                if (dayOfWeek < 0) {
+                    dayOfWeek += 7;
+                }
+                int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                int weekOfMonth = 3;
+                if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                    weekOfMonth++;
+                }
+                monthLength -= nDaysFirstWeek + 7 * 3;
+                if (monthLength > 0) {
+                    weekOfMonth++;
+                    if (monthLength > 7) {
+                        weekOfMonth++;
+                    }
+                }
+                yield weekOfMonth;
+            }
+            case DAY_OF_WEEK_IN_MONTH -> {
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                ndays = jcal.getMonthLength(d);
+                d.setDayOfMonth(1);
+                jcal.normalize(d);
+                dow1 = d.getDayOfWeek();
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                yield (ndays + 6) / 7;
+            }
+            case YEAR -> {
+                CalendarDate jd = jcal.getCalendarDate(jc.getTimeInMillis(), getZone());
+                CalendarDate d;
+                int eraIndex = getEraIndex(date);
+                int year;
+                if (eraIndex == eras.length - 1) {
+                    d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                    year = d.getYear();
+                    // Use an equivalent year for the
+                    // getYearOffsetInMillis call to avoid overflow.
+                    if (year > 400) {
+                        jd.setYear(year - 400);
+                    }
+                } else {
+                    d = jcal.getCalendarDate(eras[eraIndex + 1].getSince(getZone()) - 1, getZone());
+                    year = d.getYear();
+                    // Use the same year as d.getYear() to be
+                    // consistent with leap and common years.
+                    jd.setYear(year);
+                }
+                jcal.normalize(jd);
+                if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
+                    year--;
+                }
+                yield year;
+            }
+            default -> throw new ArrayIndexOutOfBoundsException(field);
+        };
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of the
+     * year. In the year for Long.MIN_VALUE, it's a pseudo value
+     * beyond the limit. The given CalendarDate object must have been
+     * normalized before calling this method.
+     */
+    private long getYearOffsetInMillis(CalendarDate date) {
+        long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
+        return t + date.getTimeOfDay() - date.getZoneOffset();
+    }
+
+    public Object clone() {
+        JapaneseImperialCalendar other = (JapaneseImperialCalendar) super.clone();
+
+        other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+        return zone;
+    }
+
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+    }
+
+    /**
+     * The fixed date corresponding to jdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown.
+     */
+    private transient long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * {@code complete} method.
+     *
+     * @see Calendar#complete
+     */
+    protected void computeFields() {
+        int mask = 0;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            // Specify all fields
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (tz instanceof ZoneInfo) {
+            //     zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+            if (tz instanceof libcore.util.ZoneInfo) {
+                zoneOffset = ((libcore.util.ZoneInfo)tz).getOffsetsByUtcTime(time, zoneOffsets);
+            // END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        // See if we can use jdate to avoid date calculation.
+        if (fixedDate != cachedFixedDate || fixedDate < 0) {
+            jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
+            cachedFixedDate = fixedDate;
+        }
+        int era = getEraIndex(jdate);
+        int year = jdate.getYear();
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  jdate.getMonth() - 1; // 0-based
+        int dayOfMonth = jdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK
+                          |WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = jdate.getNormalizedYear();
+            // If it's a year of an era transition, we need to handle
+            // irregular year boundaries.
+            boolean transitionYear = isTransitionYear(jdate.getNormalizedYear());
+            int dayOfYear;
+            long fixedDateJan1;
+            if (transitionYear) {
+                fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else if (normalizedYear == MIN_VALUES[YEAR]) {
+                CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                fixedDateJan1 = jcal.getFixedDate(dx);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else {
+                dayOfYear = (int) jcal.getDayOfYear(jdate);
+                fixedDateJan1 = fixedDate - dayOfYear + 1;
+            }
+            long fixedDateMonth1 = transitionYear ?
+                getFixedDateMonth1(jdate, fixedDate) : fixedDate - dayOfMonth + 1;
+
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // a transition year, we need to take care of it.
+                // Usually the previous day of the first day of a year
+                // is December 31, which is not always true in the
+                // Japanese imperial calendar system.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1;
+                LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
+                if (!(transitionYear || isTransitionYear(d.getNormalizedYear()))) {
+                    prevJan1 = fixedDateJan1 - 365;
+                    if (d.isLeapYear()) {
+                        --prevJan1;
+                    }
+                } else if (transitionYear) {
+                    if (jdate.getYear() == 1) {
+                        // As of Reiwa (since Meiji) there's no case
+                        // that there are multiple transitions in a
+                        // year.  Historically there was such
+                        // case. There might be such case again in the
+                        // future.
+                        if (era > REIWA) {
+                            CalendarDate pd = eras[era - 1].getSinceDate();
+                            if (normalizedYear == pd.getYear()) {
+                                d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
+                            }
+                        } else {
+                            d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        }
+                        jcal.normalize(d);
+                        prevJan1 = jcal.getFixedDate(d);
+                    } else {
+                        prevJan1 = fixedDateJan1 - 365;
+                        if (d.isLeapYear()) {
+                            --prevJan1;
+                        }
+                    }
+                } else {
+                    CalendarDate cd = eras[getEraIndex(jdate)].getSinceDate();
+                    d.setMonth(cd.getMonth()).setDayOfMonth(cd.getDayOfMonth());
+                    jcal.normalize(d);
+                    prevJan1 = jcal.getFixedDate(d);
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (!transitionYear) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (jdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+                    long nextJan1;
+                    if (jdate.getYear() == 1) {
+                        d.addYear(+1);
+                        d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        nextJan1 = jcal.getFixedDate(d);
+                    } else {
+                        int nextEraIndex = getEraIndex(d) + 1;
+                        CalendarDate cd = eras[nextEraIndex].getSinceDate();
+                        d.setEra(eras[nextEraIndex]);
+                        d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
+                        jcal.normalize(d);
+                        nextJan1 = jcal.getFixedDate(d);
+                    }
+                    long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                        getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `jcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                             getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @throws    IllegalArgumentException if any calendar fields are invalid.
+     */
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        int year;
+        int era;
+
+        if (isSet(ERA)) {
+            era = internalGet(ERA);
+            year = isSet(YEAR) ? internalGet(YEAR) : 1;
+        } else {
+            if (isSet(YEAR)) {
+                era = currentEra;
+                year = internalGet(YEAR);
+            } else {
+                // Equivalent to 1970 (Gregorian)
+                era = SHOWA;
+                year = 45;
+            }
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        fixedDate += getFixedDate(era, year, fieldMask);
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (zone instanceof ZoneInfo) {
+            //     ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
+            // } else {
+                zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
+            // }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        millis -= zoneOffsets[0] + zoneOffsets[1];
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    int wrongValue = internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + "=" + wrongValue
+                                                       + ", expected " + originalFields[field]);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param era era index
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(int era, int year, int fieldMask) {
+        int month = JANUARY;
+        int firstDayOfMonth = 1;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range.
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        } else {
+            if (year == 1 && era != 0) {
+                CalendarDate d = eras[era].getSinceDate();
+                month = d.getMonth() - 1;
+                firstDayOfMonth = d.getDayOfMonth();
+            }
+        }
+
+        // Adjust the base date if year is the minimum value.
+        if (year == MIN_VALUES[YEAR]) {
+            CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            int m = dx.getMonth() - 1;
+            if (month < m) {
+                month = m;
+            }
+            if (month == m) {
+                firstDayOfMonth = dx.getDayOfMonth();
+            }
+        }
+
+        LocalGregorianCalendar.Date date = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        date.setEra(era > 0 ? eras[era] : null);
+        date.setDate(year, month + 1, firstDayOfMonth);
+        jcal.normalize(date);
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = jcal.getFixedDate(date);
+
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the "first day" of the month (which may
+                // not be 1). Just add the offset if DAY_OF_MONTH is
+                // set. If the isSet call returns false, that means
+                // DAY_OF_MONTH has been selected just because of the
+                // selected combination. We don't need to add any
+                // since the default value is the "first day".
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
+                    // DAY_OF_MONTH, then subtract firstDayOfMonth.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate -= firstDayOfMonth;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                            getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                                      dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                                      dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    fixedDate = getFixedDateJan1(date, fixedDate);
+                }
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                        getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+        return fixedDate;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(LocalGregorianCalendar.Date date, long fixedDate) {
+        Era era = date.getEra();
+        if (date.getEra() != null && date.getYear() == 1) {
+            for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
+                CalendarDate d = eras[eraIndex].getSinceDate();
+                long fd = gcal.getFixedDate(d);
+                // There might be multiple era transitions in a year.
+                if (fd > fixedDate) {
+                    continue;
+                }
+                return fd;
+            }
+        }
+        CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        d.setDate(date.getNormalizedYear(), Gregorian.JANUARY, 1);
+        return gcal.getFixedDate(d);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date must be in the era transition year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(LocalGregorianCalendar.Date date,
+                                          long fixedDate) {
+        int eraIndex = getTransitionEraIndex(date);
+        if (eraIndex != -1) {
+            long transition = sinceFixedDates[eraIndex];
+            // If the given date is on or after the transition date, then
+            // return the transition date.
+            if (transition <= fixedDate) {
+                return transition;
+            }
+        }
+
+        // Otherwise, we can use the 1st day of the month.
+        return fixedDate - date.getDayOfMonth() + 1;
+    }
+
+    /**
+     * Returns a LocalGregorianCalendar.Date produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private static LocalGregorianCalendar.Date getCalendarDate(long fd) {
+        LocalGregorianCalendar.Date d = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        jcal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * Gregorian year. The year number must be normalized.
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month, int gregorianYear) {
+        return CalendarUtils.isGregorianLeapYear(gregorianYear) ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        assert jdate.isNormalized();
+        return jdate.isLeapYear() ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    private int actualMonthLength() {
+        int length = jcal.getMonthLength(jdate);
+        int eraIndex = getTransitionEraIndex(jdate);
+        if (eraIndex != -1) {
+            long transitionFixedDate = sinceFixedDates[eraIndex];
+            CalendarDate d = eras[eraIndex].getSinceDate();
+            if (transitionFixedDate <= cachedFixedDate) {
+                length -= d.getDayOfMonth() - 1;
+            } else {
+                length = d.getDayOfMonth() - 1;
+            }
+        }
+        return length;
+    }
+
+    /**
+     * Returns the index to the new era if the given date is in a
+     * transition month.  For example, if the give date is Heisei 1
+     * (1989) January 20, then the era index for Heisei is
+     * returned. Likewise, if the given date is Showa 64 (1989)
+     * January 3, then the era index for Heisei is returned. If the
+     * given date is not in any transition month, then -1 is returned.
+     */
+    private static int getTransitionEraIndex(LocalGregorianCalendar.Date date) {
+        int eraIndex = getEraIndex(date);
+        CalendarDate transitionDate = eras[eraIndex].getSinceDate();
+        if (transitionDate.getYear() == date.getNormalizedYear() &&
+            transitionDate.getMonth() == date.getMonth()) {
+            return eraIndex;
+        }
+        if (eraIndex < eras.length - 1) {
+            transitionDate = eras[++eraIndex].getSinceDate();
+            if (transitionDate.getYear() == date.getNormalizedYear() &&
+                transitionDate.getMonth() == date.getMonth()) {
+                return eraIndex;
+            }
+        }
+        return -1;
+    }
+
+    private boolean isTransitionYear(int normalizedYear) {
+        for (int i = eras.length - 1; i > 0; i--) {
+            int transitionYear = eras[i].getSinceDate().getYear();
+            if (normalizedYear == transitionYear) {
+                return true;
+            }
+            if (normalizedYear > transitionYear) {
+                break;
+            }
+        }
+        return false;
+    }
+
+    private static int getEraIndex(LocalGregorianCalendar.Date date) {
+        Era era = date.getEra();
+        for (int i = eras.length - 1; i > 0; i--) {
+            if (eras[i] == era) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private JapaneseImperialCalendar getNormalizedCalendar() {
+        JapaneseImperialCalendar jc;
+        if (isFullyNormalized()) {
+            jc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            jc = (JapaneseImperialCalendar) this.clone();
+            jc.setLenient(true);
+            jc.complete();
+        }
+        return jc;
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth(LocalGregorianCalendar.Date date) {
+        int year = date.getYear();
+        int dom = date.getDayOfMonth();
+        if (year != getMinimum(YEAR)) {
+            date.setDayOfMonth(1);
+            jcal.normalize(date);
+            int monthLength = jcal.getMonthLength(date);
+            if (dom > monthLength) {
+                date.setDayOfMonth(monthLength);
+            } else {
+                date.setDayOfMonth(dom);
+            }
+            jcal.normalize(date);
+        } else {
+            LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            LocalGregorianCalendar.Date realDate = jcal.getCalendarDate(time, getZone());
+            long tod = realDate.getTimeOfDay();
+            // Use an equivalent year.
+            realDate.addYear(+400);
+            realDate.setMonth(date.getMonth());
+            realDate.setDayOfMonth(1);
+            jcal.normalize(realDate);
+            int monthLength = jcal.getMonthLength(realDate);
+            if (dom > monthLength) {
+                realDate.setDayOfMonth(monthLength);
+            } else {
+                if (dom < d.getDayOfMonth()) {
+                    realDate.setDayOfMonth(d.getDayOfMonth());
+                } else {
+                    realDate.setDayOfMonth(dom);
+                }
+            }
+            if (realDate.getDayOfMonth() == d.getDayOfMonth() && tod < d.getTimeOfDay()) {
+                realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
+            }
+            // restore the year.
+            date.setDate(year, realDate.getMonth(), realDate.getDayOfMonth());
+            // Don't normalize date here so as not to cause underflow.
+        }
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is the current era, but a zero (unset) ERA means before Meiji.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : currentEra;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (jdate == null) {
+            jdate = jcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+    }
+}
diff --git a/android-35/java/util/JumboEnumSet.java b/android-35/java/util/JumboEnumSet.java
new file mode 100644
index 0000000..f80e505
--- /dev/null
+++ b/android-35/java/util/JumboEnumSet.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "jumbo" enum types
+ * (i.e., those with more than 64 elements).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    @java.io.Serial
+    private static final long serialVersionUID = 334349849919042784L;
+
+    /**
+     * Bit vector representation of this set.  The ith bit of the jth
+     * element of this array represents the  presence of universe[64*j +i]
+     * in this set.
+     */
+    private long elements[];
+
+    // Redundant - maintained for performance
+    private int size = 0;
+
+    JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+        elements = new long[(universe.length + 63) >>> 6];
+    }
+
+    void addRange(E from, E to) {
+        int fromIndex = from.ordinal() >>> 6;
+        int toIndex = to.ordinal() >>> 6;
+
+        if (fromIndex == toIndex) {
+            elements[fromIndex] = (-1L >>>  (from.ordinal() - to.ordinal() - 1))
+                            << from.ordinal();
+        } else {
+            elements[fromIndex] = (-1L << from.ordinal());
+            for (int i = fromIndex + 1; i < toIndex; i++)
+                elements[i] = -1;
+            elements[toIndex] = -1L >>> (63 - to.ordinal());
+        }
+        size = to.ordinal() - from.ordinal() + 1;
+    }
+
+    void addAll() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = -1;
+        elements[elements.length - 1] >>>= -universe.length;
+        size = universe.length;
+    }
+
+    void complement() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = ~elements[i];
+        elements[elements.length - 1] &= (-1L >>> -universe.length);
+        size = universe.length - size;
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "weakly consistent" iterator that will never throw {@link
+     * ConcurrentModificationException}.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the current "word"
+         * of the set not yet returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The index corresponding to unseen in the elements array.
+         */
+        int unseenIndex = 0;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        /**
+         * The index corresponding to lastReturned in the elements array.
+         */
+        int lastReturnedIndex = 0;
+
+        EnumSetIterator() {
+            unseen = elements[0];
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (unseen == 0 && unseenIndex < elements.length - 1)
+                unseen = elements[++unseenIndex];
+            return unseen != 0;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            lastReturnedIndex = unseenIndex;
+            unseen -= lastReturned;
+            return (E) universe[(lastReturnedIndex << 6)
+                                + Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        @Override
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            final long oldElements = elements[lastReturnedIndex];
+            elements[lastReturnedIndex] &= ~lastReturned;
+            if (oldElements != elements[lastReturnedIndex]) {
+                size--;
+            }
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if the set changed as a result of the call
+     *
+     * @throws NullPointerException if {@code e} is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        int eOrdinal = e.ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] |= (1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size++;
+        return result;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return {@code true} if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] &= ~(1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size--;
+        return result;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet<?> es))
+            return super.containsAll(c);
+
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        for (int i = 0; i < elements.length; i++)
+            if ((es.elements[i] & ~elements[i]) != 0)
+                return false;
+        return true;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any of
+     *     its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof JumboEnumSet<?> es))
+            return super.addAll(c);
+
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] |= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet<?> es))
+            return super.removeAll(c);
+
+        if (es.elementType != elementType)
+            return false;
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= ~es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet<?> es))
+            return super.retainAll(c);
+
+        if (es.elementType != elementType) {
+            boolean changed = (size != 0);
+            clear();
+            return changed;
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        Arrays.fill(elements, 0);
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof JumboEnumSet<?> es))
+            return super.equals(o);
+
+        if (es.elementType != elementType)
+            return size == 0 && es.size == 0;
+
+        return Arrays.equals(es.elements, elements);
+    }
+
+    /**
+     * Recalculates the size of the set.  Returns true if it's changed.
+     */
+    private boolean recalculateSize() {
+        int oldSize = size;
+        size = 0;
+        for (long elt : elements)
+            size += Long.bitCount(elt);
+
+        return size != oldSize;
+    }
+
+    public EnumSet<E> clone() {
+        JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
+        result.elements = result.elements.clone();
+        return result;
+    }
+}
diff --git a/android-35/java/util/KeyValueHolder.java b/android-35/java/util/KeyValueHolder.java
new file mode 100644
index 0000000..9dbce95
--- /dev/null
+++ b/android-35/java/util/KeyValueHolder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * An immutable container for a key and a value, suitable for use
+ * in creating and populating {@code Map} instances.
+ *
+ * <p>This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
+ *
+ * @apiNote
+ * This class is not public. Instances can be created using the
+ * {@link Map#entry Map.entry(k, v)} factory method, which is public.
+ *
+ * <p>This class differs from AbstractMap.SimpleImmutableEntry in the following ways:
+ * it is not serializable, it is final, and its key and value must be non-null.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ *
+ * @see Map#ofEntries Map.ofEntries()
+ * @since 9
+ */
[email protected]
+final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
+    @Stable
+    final K key;
+    @Stable
+    final V value;
+
+    KeyValueHolder(K k, V v) {
+        key = Objects.requireNonNull(k);
+        value = Objects.requireNonNull(v);
+    }
+
+    /**
+     * Gets the key from this holder.
+     *
+     * @return the key
+     */
+    @Override
+    public K getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from this holder.
+     *
+     * @return the value
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @param value ignored
+     * @return never returns normally
+     */
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Compares the specified object with this entry for equality.
+     * Returns {@code true} if the given object is also a map entry and
+     * the two entries' keys and values are equal. Note that key and
+     * value are non-null, so equals() can be called safely on them.
+     */
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof Map.Entry<?, ?> e
+                && key.equals(e.getKey())
+                && value.equals(e.getValue());
+    }
+
+    /**
+     * Returns the hash code value for this map entry. The hash code
+     * is {@code key.hashCode() ^ value.hashCode()}. Note that key and
+     * value are non-null, so hashCode() can be called safely on them.
+     */
+    @Override
+    public int hashCode() {
+        return key.hashCode() ^ value.hashCode();
+    }
+
+    /**
+     * Returns a String representation of this map entry.  This
+     * implementation returns the string representation of this
+     * entry's key followed by the equals character ("{@code =}")
+     * followed by the string representation of this entry's value.
+     *
+     * @return a String representation of this map entry
+     */
+    @Override
+    public String toString() {
+        return key + "=" + value;
+    }
+}
diff --git a/android-35/java/util/LinkedHashMap.java b/android-35/java/util/LinkedHashMap.java
new file mode 100644
index 0000000..9327f56
--- /dev/null
+++ b/android-35/java/util/LinkedHashMap.java
@@ -0,0 +1,1290 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.io.IOException;
+import java.util.function.Function;
+
+// Android-added: Note about spliterator order b/33945212 in Android N
+/**
+ * <p>Hash table and linked list implementation of the {@code Map} interface,
+ * with well-defined encounter order.  This implementation differs from
+ * {@code HashMap} in that it maintains a doubly-linked list running through all of
+ * its entries.  This linked list defines the encounter order (the order of iteration),
+ * which is normally the order in which keys were inserted into the map
+ * (<i>insertion-order</i>). The least recently inserted entry (the eldest) is
+ * first, and the youngest entry is last. Note that encounter order is not affected
+ * if a key is <i>re-inserted</i> into the map with the {@code put} method. (A key
+ * {@code k} is reinserted into a map {@code m} if {@code m.put(k, v)} is invoked when
+ * {@code m.containsKey(k)} would return {@code true} immediately prior to
+ * the invocation.) The reverse-ordered view of this map is in the opposite order, with
+ * the youngest entry appearing first and the eldest entry appearing last.
+ * The encounter order of entries already in the map can be changed by using
+ * the {@link #putFirst putFirst} and {@link #putLast putLast} methods.
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
+ * without incurring the increased cost associated with {@link TreeMap}.  It
+ * can be used to produce a copy of a map that has the same order as the
+ * original, regardless of the original map's implementation:
+ * <pre>{@code
+ *     void foo(Map<String, Integer> m) {
+ *         Map<String, Integer> copy = new LinkedHashMap<>(m);
+ *         ...
+ *     }
+ * }</pre>
+ * This technique is particularly useful if a module takes a map on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
+ * provided to create a linked hash map whose encounter order is the order
+ * in which its entries were last accessed, from least-recently accessed to
+ * most-recently (<i>access-order</i>).  This kind of map is well-suited to
+ * building LRU caches.  Invoking the {@code put}, {@code putIfAbsent},
+ * {@code get}, {@code getOrDefault}, {@code compute}, {@code computeIfAbsent},
+ * {@code computeIfPresent}, or {@code merge} methods results
+ * in an access to the corresponding entry (assuming it exists after the
+ * invocation completes). The {@code replace} methods only result in an access
+ * of the entry if the value is replaced.  The {@code putAll} method generates one
+ * entry access for each mapping in the specified map, in the order that
+ * key-value mappings are provided by the specified map's entry set iterator.
+ * <i>No other methods generate entry accesses.</i> Invoking these methods on the
+ * reversed view generates accesses to entries on the backing map. Note that in the
+ * reversed view, an access to an entry moves it first in encounter order.
+ * Explicit-positioning methods such as {@code putFirst} or {@code lastEntry}, whether on
+ * the map or on its reverse-ordered view, perform the positioning operation and
+ * do not generate entry accesses. Operations on the {@code keySet}, {@code values},
+ * and {@code entrySet} views or on their sequenced counterparts do <i>not</i> affect
+ * the encounter order of the backing map.
+ *
+ * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
+ * impose a policy for removing stale mappings automatically when new mappings
+ * are added to the map. Alternatively, since the "eldest" entry is the first
+ * entry in encounter order, programs can inspect and remove stale mappings through
+ * use of the {@link #firstEntry firstEntry} and {@link #pollFirstEntry pollFirstEntry}
+ * methods.
+ *
+ * <p>This class provides all of the optional {@code Map} and {@code SequencedMap} operations,
+ * and it permits null elements.  Like {@code HashMap}, it provides constant-time
+ * performance for the basic operations ({@code add}, {@code contains} and
+ * {@code remove}), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of {@code HashMap}, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over the collection-views
+ * of a {@code LinkedHashMap} requires time proportional to the <i>size</i>
+ * of the map, regardless of its capacity.  Iteration over a {@code HashMap}
+ * is likely to be more expensive, requiring time proportional to its
+ * <i>capacity</i>.
+ *
+ * <p>A linked hash map has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for {@code HashMap}.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for {@code HashMap}, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash map concurrently, and at least
+ * one of the threads modifies the map structurally, it <em>must</em> be
+ * synchronized externally.  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
+ *
+ * A structural modification is any operation that adds or deletes one or more
+ * mappings or, in the case of access-ordered linked hash maps, affects
+ * iteration order.  In insertion-ordered linked hash maps, merely changing
+ * the value associated with a key that is already contained in the map is not
+ * a structural modification.  <strong>In access-ordered linked hash maps,
+ * merely querying the map with {@code get} is a structural modification.
+ * </strong>)
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's collection view methods are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are
+ * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+ * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
+ * <em>Note</em>: The implementation of these spliterators in Android Nougat
+ * (API levels 24 and 25) uses the wrong order (inconsistent with the
+ * iterators, which use the correct order), despite reporting
+ * {@link Spliterator#ORDERED}. You may use the following code fragments
+ * to obtain a correctly ordered Spliterator on API level 24 and 25:
+ * <ul>
+ *     <li>For a Collection view {@code c = lhm.keySet()},
+ *         {@code c = lhm.entrySet()} or {@code c = lhm.values()}, use
+ *         {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())}
+ *         instead of {@code c.spliterator()}.
+ *     <li>Instead of {@code c.stream()} or {@code c.parallelStream()}, use
+ *         {@code java.util.stream.StreamSupport.stream(spliterator, false)}
+ *         to construct a (nonparallel) {@link java.util.stream.Stream} from
+ *         such a {@code Spliterator}.
+ * </ul>
+ * Note that these workarounds are only suggested where {@code lhm} is a
+ * {@code LinkedHashMap}.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @implNote
+ * The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are created from
+ * the iterators of the corresponding collections.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.4
+ */
+public class LinkedHashMap<K,V>
+    extends HashMap<K,V>
+    implements SequencedMap<K,V>, Map<K, V>
+{
+
+    /*
+     * Implementation note.  A previous version of this class was
+     * internally structured a little differently. Because superclass
+     * HashMap now uses trees for some of its nodes, class
+     * LinkedHashMap.Entry is now treated as intermediary node class
+     * that can also be converted to tree form. The name of this
+     * class, LinkedHashMap.Entry, is confusing in several ways in its
+     * current context, but cannot be changed.  Otherwise, even though
+     * it is not exported outside this package, some existing source
+     * code is known to have relied on a symbol resolution corner case
+     * rule in calls to removeEldestEntry that suppressed compilation
+     * errors due to ambiguous usages. So, we keep the name to
+     * preserve unmodified compilability.
+     *
+     * The changes in node classes also require using two fields
+     * (head, tail) rather than a pointer to a header node to maintain
+     * the doubly-linked before/after list. This class also
+     * previously used a different style of callback methods upon
+     * access, insertion, and removal.
+     */
+
+    /**
+     * HashMap.Node subclass for normal LinkedHashMap entries.
+     */
+    static class Entry<K,V> extends HashMap.Node<K,V> {
+        Entry<K,V> before, after;
+        Entry(int hash, K key, V value, Node<K,V> next) {
+            super(hash, key, value, next);
+        }
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 3801124242820219131L;
+
+    /**
+     * The head (eldest) of the doubly linked list.
+     */
+    transient LinkedHashMap.Entry<K,V> head;
+
+    /**
+     * The tail (youngest) of the doubly linked list.
+     */
+    transient LinkedHashMap.Entry<K,V> tail;
+
+    /**
+     * The iteration ordering method for this linked hash map: {@code true}
+     * for access-order, {@code false} for insertion-order.
+     *
+     * @serial
+     */
+    final boolean accessOrder;
+
+    // internal utilities
+
+    // link at the end of list
+    private void linkNodeAtEnd(LinkedHashMap.Entry<K,V> p) {
+        if (putMode == PUT_FIRST) {
+            LinkedHashMap.Entry<K,V> first = head;
+            head = p;
+            if (first == null)
+                tail = p;
+            else {
+                p.after = first;
+                first.before = p;
+            }
+        } else {
+            LinkedHashMap.Entry<K,V> last = tail;
+            tail = p;
+            if (last == null)
+                head = p;
+            else {
+                p.before = last;
+                last.after = p;
+            }
+        }
+    }
+
+    // apply src's links to dst
+    private void transferLinks(LinkedHashMap.Entry<K,V> src,
+                               LinkedHashMap.Entry<K,V> dst) {
+        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
+        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
+        if (b == null)
+            head = dst;
+        else
+            b.after = dst;
+        if (a == null)
+            tail = dst;
+        else
+            a.before = dst;
+    }
+
+    // overrides of HashMap hook methods
+
+    void reinitialize() {
+        super.reinitialize();
+        head = tail = null;
+    }
+
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
+        LinkedHashMap.Entry<K,V> p =
+            new LinkedHashMap.Entry<>(hash, key, value, e);
+        linkNodeAtEnd(p);
+        return p;
+    }
+
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+        LinkedHashMap.Entry<K,V> t =
+            new LinkedHashMap.Entry<>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        TreeNode<K,V> p = new TreeNode<>(hash, key, value, next);
+        linkNodeAtEnd(p);
+        return p;
+    }
+
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+        TreeNode<K,V> t = new TreeNode<>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    void afterNodeRemoval(Node<K,V> e) { // unlink
+        LinkedHashMap.Entry<K,V> p =
+            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+        p.before = p.after = null;
+        if (b == null)
+            head = a;
+        else
+            b.after = a;
+        if (a == null)
+            tail = b;
+        else
+            a.before = b;
+    }
+
+    void afterNodeInsertion(boolean evict) { // possibly remove eldest
+        LinkedHashMap.Entry<K,V> first;
+        if (evict && (first = head) != null && removeEldestEntry(first)) {
+            K key = first.key;
+            removeNode(hash(key), key, null, false, true);
+        }
+    }
+
+    static final int PUT_NORM = 0;
+    static final int PUT_FIRST = 1;
+    static final int PUT_LAST = 2;
+    transient int putMode = PUT_NORM;
+
+    // Called after update, but not after insertion
+    void afterNodeAccess(Node<K,V> e) {
+        LinkedHashMap.Entry<K,V> last;
+        LinkedHashMap.Entry<K,V> first;
+        if ((putMode == PUT_LAST || (putMode == PUT_NORM && accessOrder)) && (last = tail) != e) {
+            // move node to last
+            LinkedHashMap.Entry<K,V> p =
+                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+            p.after = null;
+            if (b == null)
+                head = a;
+            else
+                b.after = a;
+            if (a != null)
+                a.before = b;
+            else
+                last = b;
+            if (last == null)
+                head = p;
+            else {
+                p.before = last;
+                last.after = p;
+            }
+            tail = p;
+            ++modCount;
+        } else if (putMode == PUT_FIRST && (first = head) != e) {
+            // move node to first
+            LinkedHashMap.Entry<K,V> p =
+                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+            p.before = null;
+            if (a == null)
+                tail = b;
+            else
+                a.before = b;
+            if (b != null)
+                b.after = a;
+            else
+                first = a;
+            if (first == null)
+                tail = p;
+            else {
+                p.after = first;
+                first.before = p;
+            }
+            head = p;
+            ++modCount;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If this map already contains a mapping for this key, the mapping is relocated if necessary
+     * so that it is first in encounter order.
+     *
+     * @since 21
+     */
+    public V putFirst(K k, V v) {
+        try {
+            putMode = PUT_FIRST;
+            return this.put(k, v);
+        } finally {
+            putMode = PUT_NORM;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If this map already contains a mapping for this key, the mapping is relocated if necessary
+     * so that it is last in encounter order.
+     *
+     * @since 21
+     */
+    public V putLast(K k, V v) {
+        try {
+            putMode = PUT_LAST;
+            return this.put(k, v);
+        } finally {
+            putMode = PUT_NORM;
+        }
+    }
+
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+            s.writeObject(e.key);
+            s.writeObject(e.value);
+        }
+    }
+
+    /**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the specified initial capacity and load factor.
+     *
+     * @apiNote
+     * To create a {@code LinkedHashMap} with an initial capacity that accommodates
+     * an expected number of mappings, use {@link #newLinkedHashMap(int) newLinkedHashMap}.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the specified initial capacity and a default load factor (0.75).
+     *
+     * @apiNote
+     * To create a {@code LinkedHashMap} with an initial capacity that accommodates
+     * an expected number of mappings, use {@link #newLinkedHashMap(int) newLinkedHashMap}.
+     *
+     * @param  initialCapacity the initial capacity
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public LinkedHashMap(int initialCapacity) {
+        super(initialCapacity);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered {@code LinkedHashMap} instance
+     * with the default initial capacity (16) and load factor (0.75).
+     */
+    public LinkedHashMap() {
+        super();
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an insertion-ordered {@code LinkedHashMap} instance with
+     * the same mappings as the specified map.  The {@code LinkedHashMap}
+     * instance is created with a default load factor (0.75) and an initial
+     * capacity sufficient to hold the mappings in the specified map.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public LinkedHashMap(Map<? extends K, ? extends V> m) {
+        super();
+        accessOrder = false;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Constructs an empty {@code LinkedHashMap} instance with the
+     * specified initial capacity, load factor and ordering mode.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @param  accessOrder     the ordering mode - {@code true} for
+     *         access-order, {@code false} for insertion-order
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity,
+                         float loadFactor,
+                         boolean accessOrder) {
+        super(initialCapacity, loadFactor);
+        this.accessOrder = accessOrder;
+    }
+
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+            V v = e.value;
+            if (v == value || (value != null && value.equals(v)))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        if ((e = getNode(key)) == null)
+            return null;
+        if (accessOrder)
+            afterNodeAccess(e);
+        return e.value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+       Node<K,V> e;
+       if ((e = getNode(key)) == null)
+           return defaultValue;
+       if (accessOrder)
+           afterNodeAccess(e);
+       return e.value;
+   }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        super.clear();
+        head = tail = null;
+    }
+
+    // Android-added: eldest(), for internal use in LRU caches
+    /**
+     * Returns the eldest entry in the map, or {@code null} if the map is empty.
+     *
+     * @return eldest entry in the map, or {@code null} if the map is empty
+     *
+     * @hide
+     */
+    public Map.Entry<K, V> eldest() {
+        return head;
+    }
+
+    /**
+     * Returns {@code true} if this map should remove its eldest entry.
+     * This method is invoked by {@code put} and {@code putAll} after
+     * inserting a new entry into the map.  It provides the implementor
+     * with the opportunity to remove the eldest entry each time a new one
+     * is added.  This is useful if the map represents a cache: it allows
+     * the map to reduce memory consumption by deleting stale entries.
+     *
+     * <p>Sample use: this override will allow the map to grow up to 100
+     * entries and then delete the eldest entry each time a new entry is
+     * added, maintaining a steady state of 100 entries.
+     * <pre>
+     *     private static final int MAX_ENTRIES = 100;
+     *
+     *     protected boolean removeEldestEntry(Map.Entry eldest) {
+     *        return size() &gt; MAX_ENTRIES;
+     *     }
+     * </pre>
+     *
+     * <p>This method typically does not modify the map in any way,
+     * instead allowing the map to modify itself as directed by its
+     * return value.  It <i>is</i> permitted for this method to modify
+     * the map directly, but if it does so, it <i>must</i> return
+     * {@code false} (indicating that the map should not attempt any
+     * further modification).  The effects of returning {@code true}
+     * after modifying the map from within this method are unspecified.
+     *
+     * <p>This implementation merely returns {@code false} (so that this
+     * map acts like a normal map - the eldest element is never removed).
+     *
+     * @param    eldest The least recently inserted entry in the map, or if
+     *           this is an access-ordered map, the least recently accessed
+     *           entry.  This is the entry that will be removed if this
+     *           method returns {@code true}.  If the map was empty prior
+     *           to the {@code put} or {@code putAll} invocation resulting
+     *           in this invocation, this will be the entry that was just
+     *           inserted; in other words, if the map contains a single
+     *           entry, the eldest entry is also the newest.
+     * @return   {@code true} if the eldest entry should be removed
+     *           from the map; {@code false} if it should be retained.
+     */
+    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map. The encounter
+     * order of the keys in the view matches the encounter order of mappings of
+     * this map. The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        return sequencedKeySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * The returned view has the same characteristics as specified for the view
+     * returned by the {@link #keySet keySet} method.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public SequencedSet<K> sequencedKeySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            SequencedSet<K> sks = new LinkedKeySet(false);
+            keySet = sks;
+            return sks;
+        } else {
+            // The cast should never fail, since the only assignment of non-null to keySet is
+            // above, and assignments in AbstractMap and HashMap are in overridden methods.
+            return (SequencedSet<K>) ks;
+        }
+    }
+
+    static <K1,V1> Node<K1,V1> nsee(Node<K1,V1> node) {
+        if (node == null)
+            throw new NoSuchElementException();
+        else
+            return node;
+    }
+
+    final <T> T[] keysToArray(T[] a) {
+        return keysToArray(a, false);
+    }
+
+    final <T> T[] keysToArray(T[] a, boolean reversed) {
+        Object[] r = a;
+        int idx = 0;
+        if (reversed) {
+            for (LinkedHashMap.Entry<K,V> e = tail; e != null; e = e.before) {
+                r[idx++] = e.key;
+            }
+        } else {
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+                r[idx++] = e.key;
+            }
+        }
+        return a;
+    }
+
+    final <T> T[] valuesToArray(T[] a, boolean reversed) {
+        Object[] r = a;
+        int idx = 0;
+        if (reversed) {
+            for (LinkedHashMap.Entry<K,V> e = tail; e != null; e = e.before) {
+                r[idx++] = e.value;
+            }
+        } else {
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+                r[idx++] = e.value;
+            }
+        }
+        return a;
+    }
+
+    final class LinkedKeySet extends AbstractSet<K> implements SequencedSet<K> {
+        final boolean reversed;
+        LinkedKeySet(boolean reversed)          { this.reversed = reversed; }
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<K> iterator() {
+            return new LinkedKeyIterator(reversed);
+        }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator()  {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+
+        public Object[] toArray() {
+            return keysToArray(new Object[size], reversed);
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return keysToArray(prepareArray(a), reversed);
+        }
+
+        public final void forEach(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            if (reversed) {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = tail; e != null && modCount == mc; e = e.before)
+                    action.accept(e.key);
+            } else {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                    action.accept(e.key);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+        public final void addFirst(K k) { throw new UnsupportedOperationException(); }
+        public final void addLast(K k) { throw new UnsupportedOperationException(); }
+        public final K getFirst() { return nsee(reversed ? tail : head).key; }
+        public final K getLast() { return nsee(reversed ? head : tail).key; }
+        public final K removeFirst() {
+            var node = nsee(reversed ? tail : head);
+            removeNode(node.hash, node.key, null, false, false);
+            return node.key;
+        }
+        public final K removeLast() {
+            var node = nsee(reversed ? head : tail);
+            removeNode(node.hash, node.key, null, false, false);
+            return node.key;
+        }
+        public SequencedSet<K> reversed() {
+            if (reversed) {
+                return LinkedHashMap.this.sequencedKeySet();
+            } else {
+                return new LinkedKeySet(true);
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map. The
+     * encounter order of values in the view matches the encounter order of entries in
+     * this map. The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        return sequencedValues();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * The returned view has the same characteristics as specified for the view
+     * returned by the {@link #values values} method.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public SequencedCollection<V> sequencedValues() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            SequencedCollection<V> svs = new LinkedValues(false);
+            values = svs;
+            return svs;
+        } else {
+            // The cast should never fail, since the only assignment of non-null to values is
+            // above, and assignments in AbstractMap and HashMap are in overridden methods.
+            return (SequencedCollection<V>) vs;
+        }
+    }
+
+    final class LinkedValues extends AbstractCollection<V> implements SequencedCollection<V> {
+        final boolean reversed;
+        LinkedValues(boolean reversed)          { this.reversed = reversed; }
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<V> iterator() {
+            return new LinkedValueIterator(reversed);
+        }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED);
+        }
+
+        public Object[] toArray() {
+            return valuesToArray(new Object[size], reversed);
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return valuesToArray(prepareArray(a), reversed);
+        }
+
+        public final void forEach(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            if (reversed) {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = tail; e != null && modCount == mc; e = e.before)
+                    action.accept(e.value);
+            } else {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                    action.accept(e.value);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+        public final void addFirst(V v) { throw new UnsupportedOperationException(); }
+        public final void addLast(V v) { throw new UnsupportedOperationException(); }
+        public final V getFirst() { return nsee(reversed ? tail : head).value; }
+        public final V getLast() { return nsee(reversed ? head : tail).value; }
+        public final V removeFirst() {
+            var node = nsee(reversed ? tail : head);
+            removeNode(node.hash, node.key, null, false, false);
+            return node.value;
+        }
+        public final V removeLast() {
+            var node = nsee(reversed ? head : tail);
+            removeNode(node.hash, node.key, null, false, false);
+            return node.value;
+        }
+        public SequencedCollection<V> reversed() {
+            if (reversed) {
+                return LinkedHashMap.this.sequencedValues();
+            } else {
+                return new LinkedValues(true);
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map. The encounter
+     * order of the view matches the encounter order of entries of this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        return sequencedEntrySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * The returned view has the same characteristics as specified for the view
+     * returned by the {@link #entrySet entrySet} method.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public SequencedSet<Map.Entry<K, V>> sequencedEntrySet() {
+        Set<Map.Entry<K, V>> es = entrySet;
+        if (es == null) {
+            SequencedSet<Map.Entry<K, V>> ses = new LinkedEntrySet(false);
+            entrySet = ses;
+            return ses;
+        } else {
+            // The cast should never fail, since the only assignment of non-null to entrySet is
+            // above, and assignments in HashMap are in overridden methods.
+            return (SequencedSet<Map.Entry<K, V>>) es;
+        }
+    }
+
+    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>>
+        implements SequencedSet<Map.Entry<K,V>> {
+        final boolean reversed;
+        LinkedEntrySet(boolean reversed)        { this.reversed = reversed; }
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new LinkedEntryIterator(reversed);
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> e))
+                return false;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry<?, ?> e) {
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            if (reversed) {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = tail; e != null && mc == modCount; e = e.before)
+                    action.accept(e);
+            } else {
+                // Android-changed: Detect changes to modCount early.
+                for (LinkedHashMap.Entry<K,V> e = head; (e != null && mc == modCount); e = e.after)
+                    action.accept(e);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+        final Node<K,V> nsee(Node<K,V> e) {
+            if (e == null)
+                throw new NoSuchElementException();
+            else
+                return e;
+        }
+        public final void addFirst(Map.Entry<K,V> e) { throw new UnsupportedOperationException(); }
+        public final void addLast(Map.Entry<K,V> e) { throw new UnsupportedOperationException(); }
+        public final Map.Entry<K,V> getFirst() { return nsee(reversed ? tail : head); }
+        public final Map.Entry<K,V> getLast() { return nsee(reversed ? head : tail); }
+        public final Map.Entry<K,V> removeFirst() {
+            var node = nsee(reversed ? tail : head);
+            removeNode(node.hash, node.key, null, false, false);
+            return node;
+        }
+        public final Map.Entry<K,V> removeLast() {
+            var node = nsee(reversed ? head : tail);
+            removeNode(node.hash, node.key, null, false, false);
+            return node;
+        }
+        public SequencedSet<Map.Entry<K,V>> reversed() {
+            if (reversed) {
+                return LinkedHashMap.this.sequencedEntrySet();
+            } else {
+                return new LinkedEntrySet(true);
+            }
+        }
+    }
+
+    // Map overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMap.Entry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            action.accept(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMap.Entry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            e.value = function.apply(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    // Iterators
+
+    abstract class LinkedHashIterator {
+        LinkedHashMap.Entry<K,V> next;
+        LinkedHashMap.Entry<K,V> current;
+        int expectedModCount;
+        boolean reversed;
+
+        LinkedHashIterator(boolean reversed) {
+            this.reversed = reversed;
+            next = reversed ? tail : head;
+            expectedModCount = modCount;
+            current = null;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final LinkedHashMap.Entry<K,V> nextNode() {
+            LinkedHashMap.Entry<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            current = e;
+            next = reversed ? e.before : e.after;
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            removeNode(p.hash, p.key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class LinkedKeyIterator extends LinkedHashIterator
+        implements Iterator<K> {
+        LinkedKeyIterator(boolean reversed) { super(reversed); }
+        public final K next() { return nextNode().getKey(); }
+    }
+
+    final class LinkedValueIterator extends LinkedHashIterator
+        implements Iterator<V> {
+        LinkedValueIterator(boolean reversed) { super(reversed); }
+        public final V next() { return nextNode().value; }
+    }
+
+    final class LinkedEntryIterator extends LinkedHashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        LinkedEntryIterator(boolean reversed) { super(reversed); }
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+    /**
+     * Creates a new, empty, insertion-ordered LinkedHashMap suitable for the expected number of mappings.
+     * The returned map uses the default load factor of 0.75, and its initial capacity is
+     * generally large enough so that the expected number of mappings can be added
+     * without resizing the map.
+     *
+     * @param numMappings the expected number of mappings
+     * @param <K>         the type of keys maintained by the new map
+     * @param <V>         the type of mapped values
+     * @return the newly created map
+     * @throws IllegalArgumentException if numMappings is negative
+     * @since 19
+     */
+    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int numMappings) {
+        if (numMappings < 0) {
+            throw new IllegalArgumentException("Negative number of mappings: " + numMappings);
+        }
+        return new LinkedHashMap<>(HashMap.calculateHashMapCapacity(numMappings));
+    }
+
+    // Reversed View
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Modifications to the reversed view and its map views are permitted and will be
+     * propagated to this map. In addition, modifications to this map will be visible
+     * in the reversed view and its map views.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public SequencedMap<K, V> reversed() {
+        return new ReversedLinkedHashMapView<>(this);
+    }
+
+    static class ReversedLinkedHashMapView<K, V> extends AbstractMap<K, V>
+                                                 implements SequencedMap<K, V> {
+        final LinkedHashMap<K, V> base;
+
+        ReversedLinkedHashMapView(LinkedHashMap<K, V> lhm) {
+            base = lhm;
+        }
+
+        // Object
+        // inherit toString() from AbstractMap; it depends on entrySet()
+
+        public boolean equals(Object o) {
+            return base.equals(o);
+        }
+
+        public int hashCode() {
+            return base.hashCode();
+        }
+
+        // Map
+
+        public int size() {
+            return base.size();
+        }
+
+        public boolean isEmpty() {
+            return base.isEmpty();
+        }
+
+        public boolean containsKey(Object key) {
+            return base.containsKey(key);
+        }
+
+        public boolean containsValue(Object value) {
+            return base.containsValue(value);
+        }
+
+        public V get(Object key) {
+            return base.get(key);
+        }
+
+        public V put(K key, V value) {
+            return base.put(key, value);
+        }
+
+        public V remove(Object key) {
+            return base.remove(key);
+        }
+
+        public void putAll(Map<? extends K, ? extends V> m) {
+            base.putAll(m);
+        }
+
+        public void clear() {
+            base.clear();
+        }
+
+        public Set<K> keySet() {
+            return base.sequencedKeySet().reversed();
+        }
+
+        public Collection<V> values() {
+            return base.sequencedValues().reversed();
+        }
+
+        public Set<Entry<K, V>> entrySet() {
+            return base.sequencedEntrySet().reversed();
+        }
+
+        public V getOrDefault(Object key, V defaultValue) {
+            return base.getOrDefault(key, defaultValue);
+        }
+
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = base.modCount;
+            for (LinkedHashMap.Entry<K,V> e = base.tail; e != null; e = e.before)
+                action.accept(e.key, e.value);
+            if (base.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            if (function == null)
+                throw new NullPointerException();
+            int mc = base.modCount;
+            for (LinkedHashMap.Entry<K,V> e = base.tail; e != null; e = e.before)
+                e.value = function.apply(e.key, e.value);
+            if (base.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public V putIfAbsent(K key, V value) {
+            return base.putIfAbsent(key, value);
+        }
+
+        public boolean remove(Object key, Object value) {
+            return base.remove(key, value);
+        }
+
+        public boolean replace(K key, V oldValue, V newValue) {
+            return base.replace(key, oldValue, newValue);
+        }
+
+        public V replace(K key, V value) {
+            return base.replace(key, value);
+        }
+
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            return base.computeIfAbsent(key, mappingFunction);
+        }
+
+        public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return base.computeIfPresent(key, remappingFunction);
+        }
+
+        public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return base.compute(key, remappingFunction);
+        }
+
+        public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            return base.merge(key, value, remappingFunction);
+        }
+
+        // SequencedMap
+
+        public SequencedMap<K, V> reversed() {
+            return base;
+        }
+
+        public Entry<K, V> firstEntry() {
+            return base.lastEntry();
+        }
+
+        public Entry<K, V> lastEntry() {
+            return base.firstEntry();
+        }
+
+        public Entry<K, V> pollFirstEntry() {
+            return base.pollLastEntry();
+        }
+
+        public Entry<K, V> pollLastEntry() {
+            return base.pollFirstEntry();
+        }
+
+        public V putFirst(K k, V v) {
+            return base.putLast(k, v);
+        }
+
+        public V putLast(K k, V v) {
+            return base.putFirst(k, v);
+        }
+    }
+}
diff --git a/android-35/java/util/LinkedHashSet.java b/android-35/java/util/LinkedHashSet.java
new file mode 100644
index 0000000..fba8b57
--- /dev/null
+++ b/android-35/java/util/LinkedHashSet.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>Hash table and linked list implementation of the {@code Set} interface,
+ * with well-defined encounter order.  This implementation differs from
+ * {@code HashSet} in that it maintains a doubly-linked list running through
+ * all of its entries.  This linked list defines the encounter order (iteration
+ * order), which is the order in which elements were inserted into the set
+ * (<i>insertion-order</i>). The least recently inserted element (the eldest) is
+ * first, and the youngest element is last. Note that encounter order is <i>not</i> affected
+ * if an element is <i>re-inserted</i> into the set with the {@code add} method.
+ * (An element {@code e} is reinserted into a set {@code s} if {@code s.add(e)} is
+ * invoked when {@code s.contains(e)} would return {@code true} immediately prior to
+ * the invocation.) The reverse-ordered view of this set is in the opposite order, with
+ * the youngest element appearing first and the eldest element appearing last. The encounter
+ * order of elements already in the set can be changed by using the
+ * {@link #addFirst addFirst} and {@link #addLast addLast} methods.
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashSet}, without incurring the
+ * increased cost associated with {@link TreeSet}.  It can be used to
+ * produce a copy of a set that has the same order as the original, regardless
+ * of the original set's implementation:
+ * <pre>{@code
+ *     void foo(Set<String> s) {
+ *         Set<String> copy = new LinkedHashSet<>(s);
+ *         ...
+ *     }
+ * }</pre>
+ * This technique is particularly useful if a module takes a set on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>This class provides all of the optional {@link Set} and {@link SequencedSet}
+ * operations, and it permits null elements. Like {@code HashSet}, it provides constant-time
+ * performance for the basic operations ({@code add}, {@code contains} and
+ * {@code remove}), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of {@code HashSet}, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over a {@code LinkedHashSet}
+ * requires time proportional to the <i>size</i> of the set, regardless of
+ * its capacity.  Iteration over a {@code HashSet} is likely to be more
+ * expensive, requiring time proportional to its <i>capacity</i>.
+ *
+ * <p>A linked hash set has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for {@code HashSet}.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for {@code HashSet}, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash set concurrently, and at least
+ * one of the threads modifies the set, it <em>must</em> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} method are
+ * <em>fail-fast</em>: if the set is modified at any time after the iterator
+ * is created, in any way except through the iterator's own {@code remove}
+ * method, the iterator will throw a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     Hashtable
+ * @since   1.4
+ */
+
+public class LinkedHashSet<E>
+    extends HashSet<E>
+    implements SequencedSet<E>, Set<E>, Cloneable, java.io.Serializable {
+
+    @java.io.Serial
+    private static final long serialVersionUID = -2851667679971038690L;
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and load factor.
+     *
+     * @apiNote
+     * To create a {@code LinkedHashSet} with an initial capacity that accommodates
+     * an expected number of elements, use {@link #newLinkedHashSet(int) newLinkedHashSet}.
+     *
+     * @param      initialCapacity the initial capacity of the linked hash set
+     * @param      loadFactor      the load factor of the linked hash set
+     * @throws     IllegalArgumentException  if the initial capacity is less
+     *               than zero, or if the load factor is nonpositive
+     */
+    public LinkedHashSet(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @apiNote
+     * To create a {@code LinkedHashSet} with an initial capacity that accommodates
+     * an expected number of elements, use {@link #newLinkedHashSet(int) newLinkedHashSet}.
+     *
+     * @param   initialCapacity   the initial capacity of the LinkedHashSet
+     * @throws  IllegalArgumentException if the initial capacity is less
+     *              than zero
+     */
+    public LinkedHashSet(int initialCapacity) {
+        super(initialCapacity, .75f, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public LinkedHashSet() {
+        super(16, .75f, true);
+    }
+
+    /**
+     * Constructs a new linked hash set with the same elements as the
+     * specified collection.  The linked hash set is created with an initial
+     * capacity sufficient to hold the elements in the specified collection
+     * and the default load factor (0.75).
+     *
+     * @param c  the collection whose elements are to be placed into
+     *           this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedHashSet(Collection<? extends E> c) {
+        super(HashMap.calculateHashMapCapacity(Math.max(c.size(), 12)), .75f, true);
+        addAll(c);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, and {@code ORDERED}.  Implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
+    }
+
+    /**
+     * Creates a new, empty LinkedHashSet suitable for the expected number of elements.
+     * The returned set uses the default load factor of 0.75, and its initial capacity is
+     * generally large enough so that the expected number of elements can be added
+     * without resizing the set.
+     *
+     * @param numElements    the expected number of elements
+     * @param <T>         the type of elements maintained by the new set
+     * @return the newly created set
+     * @throws IllegalArgumentException if numElements is negative
+     * @since 19
+     */
+    public static <T> LinkedHashSet<T> newLinkedHashSet(int numElements) {
+        if (numElements < 0) {
+            throw new IllegalArgumentException("Negative number of elements: " + numElements);
+        }
+        return new LinkedHashSet<>(HashMap.calculateHashMapCapacity(numElements));
+    }
+
+    @SuppressWarnings("unchecked")
+    LinkedHashMap<E, Object> map() {
+        return (LinkedHashMap<E, Object>) map;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If this set already contains the element, it is relocated if necessary so that it is
+     * first in encounter order.
+     *
+     * @since 21
+     */
+    public void addFirst(E e) {
+        map().putFirst(e, PRESENT);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If this set already contains the element, it is relocated if necessary so that it is
+     * last in encounter order.
+     *
+     * @since 21
+     */
+    public void addLast(E e) {
+        map().putLast(e, PRESENT);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getFirst() {
+        return map().sequencedKeySet().getFirst();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getLast() {
+        return map().sequencedKeySet().getLast();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeFirst() {
+        return map().sequencedKeySet().removeFirst();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeLast() {
+        return map().sequencedKeySet().removeLast();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Modifications to the reversed view are permitted and will be propagated to this set.
+     * In addition, modifications to this set will be visible in the reversed view.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public SequencedSet<E> reversed() {
+        class ReverseLinkedHashSetView extends AbstractSet<E> implements SequencedSet<E> {
+            public int size()                  { return LinkedHashSet.this.size(); }
+            public Iterator<E> iterator()      { return map().sequencedKeySet().reversed().iterator(); }
+            public boolean add(E e)            { return LinkedHashSet.this.add(e); }
+            public void addFirst(E e)          { LinkedHashSet.this.addLast(e); }
+            public void addLast(E e)           { LinkedHashSet.this.addFirst(e); }
+            public E getFirst()                { return LinkedHashSet.this.getLast(); }
+            public E getLast()                 { return LinkedHashSet.this.getFirst(); }
+            public E removeFirst()             { return LinkedHashSet.this.removeLast(); }
+            public E removeLast()              { return LinkedHashSet.this.removeFirst(); }
+            public SequencedSet<E> reversed()  { return LinkedHashSet.this; }
+            public Object[] toArray() { return map().keysToArray(new Object[map.size()], true); }
+            public <T> T[] toArray(T[] a) { return map().keysToArray(map.prepareArray(a), true); }
+        }
+
+        return new ReverseLinkedHashSetView();
+    }
+}
diff --git a/android-35/java/util/LinkedList.java b/android-35/java/util/LinkedList.java
new file mode 100644
index 0000000..d7c67c9
--- /dev/null
+++ b/android-35/java/util/LinkedList.java
@@ -0,0 +1,1539 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+
+/**
+ * Doubly-linked list implementation of the {@code List} and {@code Deque}
+ * interfaces.  Implements all optional list operations, and permits all
+ * elements (including {@code null}).
+ *
+ * <p>All of the operations perform as could be expected for a doubly-linked
+ * list.  Operations that index into the list will traverse the list from
+ * the beginning or the end, whichever is closer to the specified index.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked list concurrently, and at least
+ * one of the threads modifies the list structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more elements; merely setting the value of
+ * an element is not a structural modification.)  This is typically
+ * accomplished by synchronizing on some object that naturally
+ * encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new LinkedList(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} and
+ * {@code listIterator} methods are <i>fail-fast</i>: if the list is
+ * structurally modified at any time after the iterator is created, in
+ * any way except through the Iterator's own {@code remove} or
+ * {@code add} methods, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than
+ * risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see     List
+ * @see     ArrayList
+ * @since 1.2
+ * @param <E> the type of elements held in this collection
+ */
+
+public class LinkedList<E>
+    extends AbstractSequentialList<E>
+    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
+{
+    transient int size = 0;
+
+    /**
+     * Pointer to first node.
+     */
+    transient Node<E> first;
+
+    /**
+     * Pointer to last node.
+     */
+    transient Node<E> last;
+
+    /*
+    void dataStructureInvariants() {
+        assert (size == 0)
+            ? (first == null && last == null)
+            : (first.prev == null && last.next == null);
+    }
+    */
+
+    /**
+     * Constructs an empty list.
+     */
+    public LinkedList() {
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param  c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedList(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> f = first;
+        final Node<E> newNode = new Node<>(null, e, f);
+        first = newNode;
+        if (f == null)
+            last = newNode;
+        else
+            f.prev = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Links e as last element.
+     */
+    void linkLast(E e) {
+        final Node<E> l = last;
+        final Node<E> newNode = new Node<>(l, e, null);
+        last = newNode;
+        if (l == null)
+            first = newNode;
+        else
+            l.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Inserts element e before non-null Node succ.
+     */
+    void linkBefore(E e, Node<E> succ) {
+        // assert succ != null;
+        final Node<E> pred = succ.prev;
+        final Node<E> newNode = new Node<>(pred, e, succ);
+        succ.prev = newNode;
+        if (pred == null)
+            first = newNode;
+        else
+            pred.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Unlinks non-null first node f.
+     */
+    private E unlinkFirst(Node<E> f) {
+        // assert f == first && f != null;
+        final E element = f.item;
+        final Node<E> next = f.next;
+        f.item = null;
+        f.next = null; // help GC
+        first = next;
+        if (next == null)
+            last = null;
+        else
+            next.prev = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null last node l.
+     */
+    private E unlinkLast(Node<E> l) {
+        // assert l == last && l != null;
+        final E element = l.item;
+        final Node<E> prev = l.prev;
+        l.item = null;
+        l.prev = null; // help GC
+        last = prev;
+        if (prev == null)
+            first = null;
+        else
+            prev.next = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null node x.
+     */
+    E unlink(Node<E> x) {
+        // assert x != null;
+        final E element = x.item;
+        final Node<E> next = x.next;
+        final Node<E> prev = x.prev;
+
+        if (prev == null) {
+            first = next;
+        } else {
+            prev.next = next;
+            x.prev = null;
+        }
+
+        if (next == null) {
+            last = prev;
+        } else {
+            next.prev = prev;
+            x.next = null;
+        }
+
+        x.item = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Returns the first element in this list.
+     *
+     * @return the first element in this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E getFirst() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return f.item;
+    }
+
+    /**
+     * Returns the last element in this list.
+     *
+     * @return the last element in this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E getLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return l.item;
+    }
+
+    /**
+     * Removes and returns the first element from this list.
+     *
+     * @return the first element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeFirst() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return unlinkFirst(f);
+    }
+
+    /**
+     * Removes and returns the last element from this list.
+     *
+     * @return the last element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return unlinkLast(l);
+    }
+
+    /**
+     * Inserts the specified element at the beginning of this list.
+     *
+     * @param e the element to add
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If this list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator.  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in
+     * progress.  (Note that this will occur if the specified collection is
+     * this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        return addAll(size, c);
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element
+     *              from the specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        checkPositionIndex(index);
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+
+        Node<E> pred, succ;
+        if (index == size) {
+            succ = null;
+            pred = last;
+        } else {
+            succ = node(index);
+            pred = succ.prev;
+        }
+
+        for (Object o : a) {
+            @SuppressWarnings("unchecked") E e = (E) o;
+            Node<E> newNode = new Node<>(pred, e, null);
+            if (pred == null)
+                first = newNode;
+            else
+                pred.next = newNode;
+            pred = newNode;
+        }
+
+        if (succ == null) {
+            last = pred;
+        } else {
+            pred.next = succ;
+            succ.prev = pred;
+        }
+
+        size += numNew;
+        modCount++;
+        return true;
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
+     */
+    public void clear() {
+        // Clearing all of the links between nodes is "unnecessary", but:
+        // - helps a generational GC if the discarded nodes inhabit
+        //   more than one generation
+        // - is sure to free memory even if there is a reachable Iterator
+        for (Node<E> x = first; x != null; ) {
+            Node<E> next = x.next;
+            x.item = null;
+            x.next = null;
+            x.prev = null;
+            x = next;
+        }
+        first = last = null;
+        size = 0;
+        modCount++;
+    }
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        checkElementIndex(index);
+        return node(index).item;
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        checkElementIndex(index);
+        Node<E> x = node(index);
+        E oldVal = x.item;
+        x.item = element;
+        return oldVal;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        checkPositionIndex(index);
+
+        if (index == size)
+            linkLast(element);
+        else
+            linkBefore(element, node(index));
+    }
+
+    /**
+     * Removes the element at the specified position in this list.  Shifts any
+     * subsequent elements to the left (subtracts one from their indices).
+     * Returns the element that was removed from the list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        checkElementIndex(index);
+        return unlink(node(index));
+    }
+
+    /**
+     * Tells if the argument is the index of an existing element.
+     */
+    private boolean isElementIndex(int index) {
+        return index >= 0 && index < size;
+    }
+
+    /**
+     * Tells if the argument is the index of a valid position for an
+     * iterator or an add operation.
+     */
+    private boolean isPositionIndex(int index) {
+        return index >= 0 && index <= size;
+    }
+
+    /**
+     * Constructs an IndexOutOfBoundsException detail message.
+     * Of the many possible refactorings of the error handling code,
+     * this "outlining" performs best with both server and client VMs.
+     */
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size;
+    }
+
+    private void checkElementIndex(int index) {
+        if (!isElementIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private void checkPositionIndex(int index) {
+        if (!isPositionIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    /**
+     * Returns the (non-null) Node at the specified element index.
+     */
+    Node<E> node(int index) {
+        // assert isElementIndex(index);
+
+        if (index < (size >> 1)) {
+            Node<E> x = first;
+            for (int i = 0; i < index; i++)
+                x = x.next;
+            return x;
+        } else {
+            Node<E> x = last;
+            for (int i = size - 1; i > index; i--)
+                x = x.prev;
+            return x;
+        }
+    }
+
+    // Search Operations
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int indexOf(Object o) {
+        int index = 0;
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null)
+                    return index;
+                index++;
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item))
+                    return index;
+                index++;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int lastIndexOf(Object o) {
+        int index = size;
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (x.item == null)
+                    return index;
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (o.equals(x.item))
+                    return index;
+            }
+        }
+        return -1;
+    }
+
+    // Queue operations.
+
+    /**
+     * Retrieves, but does not remove, the head (first element) of this list.
+     *
+     * @return the head of this list, or {@code null} if this list is empty
+     * @since 1.5
+     */
+    public E peek() {
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+    }
+
+    /**
+     * Retrieves, but does not remove, the head (first element) of this list.
+     *
+     * @return the head of this list
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.5
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list, or {@code null} if this list is empty
+     * @since 1.5
+     */
+    public E poll() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.5
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Adds the specified element as the tail (last element) of this list.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @since 1.5
+     */
+    public boolean offer(E e) {
+        return add(e);
+    }
+
+    // Deque operations
+    /**
+     * Inserts the specified element at the front of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @since 1.6
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @since 1.6
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Retrieves, but does not remove, the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+     }
+
+    /**
+     * Retrieves, but does not remove, the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : l.item;
+    }
+
+    /**
+     * Retrieves and removes the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : unlinkLast(l);
+    }
+
+    /**
+     * Pushes an element onto the stack represented by this list.  In other
+     * words, inserts the element at the front of this list.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @since 1.6
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this list.  In other
+     * words, removes and returns the first element of this list.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this list (which is the top
+     *         of the stack represented by this list)
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.6
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        return remove(o);
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a list-iterator of the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * Obeys the general contract of {@code List.listIterator(int)}.<p>
+     *
+     * The list-iterator is <i>fail-fast</i>: if the list is structurally
+     * modified at any time after the Iterator is created, in any way except
+     * through the list-iterator's own {@code remove} or {@code add}
+     * methods, the list-iterator will throw a
+     * {@code ConcurrentModificationException}.  Thus, in the face of
+     * concurrent modification, the iterator fails quickly and cleanly, rather
+     * than risking arbitrary, non-deterministic behavior at an undetermined
+     * time in the future.
+     *
+     * @param index index of the first element to be returned from the
+     *              list-iterator (by a call to {@code next})
+     * @return a ListIterator of the elements in this list (in proper
+     *         sequence), starting at the specified position in the list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @see List#listIterator(int)
+     */
+    public ListIterator<E> listIterator(int index) {
+        checkPositionIndex(index);
+        return new ListItr(index);
+    }
+
+    private class ListItr implements ListIterator<E> {
+        private Node<E> lastReturned;
+        private Node<E> next;
+        private int nextIndex;
+        private int expectedModCount = modCount;
+
+        ListItr(int index) {
+            // assert isPositionIndex(index);
+            next = (index == size) ? null : node(index);
+            nextIndex = index;
+        }
+
+        public boolean hasNext() {
+            return nextIndex < size;
+        }
+
+        public E next() {
+            checkForComodification();
+            if (!hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = next;
+            next = next.next;
+            nextIndex++;
+            return lastReturned.item;
+        }
+
+        public boolean hasPrevious() {
+            return nextIndex > 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            if (!hasPrevious())
+                throw new NoSuchElementException();
+
+            lastReturned = next = (next == null) ? last : next.prev;
+            nextIndex--;
+            return lastReturned.item;
+        }
+
+        public int nextIndex() {
+            return nextIndex;
+        }
+
+        public int previousIndex() {
+            return nextIndex - 1;
+        }
+
+        public void remove() {
+            checkForComodification();
+            if (lastReturned == null)
+                throw new IllegalStateException();
+
+            Node<E> lastNext = lastReturned.next;
+            unlink(lastReturned);
+            if (next == lastReturned)
+                next = lastNext;
+            else
+                nextIndex--;
+            lastReturned = null;
+            expectedModCount++;
+        }
+
+        public void set(E e) {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            checkForComodification();
+            lastReturned.item = e;
+        }
+
+        public void add(E e) {
+            checkForComodification();
+            lastReturned = null;
+            if (next == null)
+                linkLast(e);
+            else
+                linkBefore(e, next);
+            nextIndex++;
+            expectedModCount++;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (modCount == expectedModCount && nextIndex < size) {
+                action.accept(next.item);
+                lastReturned = next;
+                next = next.next;
+                nextIndex++;
+            }
+            checkForComodification();
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private static class Node<E> {
+        E item;
+        Node<E> next;
+        Node<E> prev;
+
+        Node(Node<E> prev, E element, Node<E> next) {
+            this.item = element;
+            this.next = next;
+            this.prev = prev;
+        }
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    /**
+     * Adapter to provide descending iterators via ListItr.previous
+     */
+    private class DescendingIterator implements Iterator<E> {
+        private final ListItr itr = new ListItr(size());
+        public boolean hasNext() {
+            return itr.hasPrevious();
+        }
+        public E next() {
+            return itr.previous();
+        }
+        public void remove() {
+            itr.remove();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private LinkedList<E> superClone() {
+        try {
+            return (LinkedList<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this {@code LinkedList}. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this {@code LinkedList} instance
+     */
+    public Object clone() {
+        LinkedList<E> clone = superClone();
+
+        // Put clone into "virgin" state
+        clone.first = clone.last = null;
+        clone.size = 0;
+        clone.modCount = 0;
+
+        // Initialize clone with our elements
+        for (Node<E> x = first; x != null; x = x.next)
+            clone.add(x.item);
+
+        return clone;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list
+     *         in proper sequence
+     */
+    public Object[] toArray() {
+        Object[] result = new Object[size];
+        int i = 0;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+        return result;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If the list fits in the specified array with room to spare (i.e.,
+     * the array has more elements than the list), the element in the array
+     * immediately following the end of the list is set to {@code null}.
+     * (This is useful in determining the length of the list <i>only</i> if
+     * the caller knows that the list does not contain any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size)
+            a = (T[])java.lang.reflect.Array.newInstance(
+                                a.getClass().getComponentType(), size);
+        int i = 0;
+        Object[] result = a;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+
+        if (a.length > size)
+            a[size] = null;
+
+        return a;
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * Saves the state of this {@code LinkedList} instance to a stream
+     * (that is, serializes it).
+     *
+     * @serialData The size of the list (the number of elements it
+     *             contains) is emitted (int), followed by all of its
+     *             elements (each an Object) in the proper order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (Node<E> x = first; x != null; x = x.next)
+            s.writeObject(x.item);
+    }
+
+    /**
+     * Reconstitutes this {@code LinkedList} instance from a stream
+     * (that is, deserializes it).
+     */
+    @SuppressWarnings("unchecked")
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden serialization magic
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            linkLast((E)s.readObject());
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}
+     * and implements {@code trySplit} to permit limited parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new LLSpliterator<>(this, -1, 0);
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LLSpliterator<E> implements Spliterator<E> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedList<E> list; // null OK unless traversed
+        Node<E> current;      // current node; null until initialized
+        int est;              // size estimate; -1 until first needed
+        int expectedModCount; // initialized when est set
+        int batch;            // batch size for splits
+
+        LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
+            this.list = list;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEst() {
+            int s; // force initialization
+            final LinkedList<E> lst;
+            if ((s = est) < 0) {
+                if ((lst = list) == null)
+                    s = est = 0;
+                else {
+                    expectedModCount = lst.modCount;
+                    current = lst.first;
+                    s = est = lst.size;
+                }
+            }
+            return s;
+        }
+
+        public long estimateSize() { return (long) getEst(); }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            int s = getEst();
+            if (s > 1 && (p = current) != null) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
+                current = p;
+                batch = j;
+                est = s - j;
+                return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p; int n;
+            if (action == null) throw new NullPointerException();
+            if ((n = getEst()) > 0 && (p = current) != null) {
+                current = null;
+                est = 0;
+                do {
+                    E e = p.item;
+                    p = p.next;
+                    action.accept(e);
+                } while (p != null && --n > 0);
+            }
+            if (list.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            if (getEst() > 0 && (p = current) != null) {
+                --est;
+                E e = p.item;
+                current = p.next;
+                action.accept(e);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Modifications to the reversed view are permitted and will be propagated to this list.
+     * In addition, modifications to this list will be visible in the reversed view.
+     *
+     * @return {@inheritDoc}
+     * @since 21
+     */
+    public LinkedList<E> reversed() {
+        return new ReverseOrderLinkedListView<>(this, super.reversed(), Deque.super.reversed());
+    }
+
+    // all operations are delegated to the reverse-ordered views.
+    // TODO audit all overridden methods
+    @SuppressWarnings("serial")
+    static class ReverseOrderLinkedListView<E> extends LinkedList<E> implements java.io.Externalizable {
+        final LinkedList<E> list;
+        final List<E> rlist;
+        final Deque<E> rdeque;
+
+        ReverseOrderLinkedListView(LinkedList<E> list, List<E> rlist, Deque<E> rdeque) {
+            this.list = list;
+            this.rlist = rlist;
+            this.rdeque = rdeque;
+        }
+
+        public String toString() {
+            return rlist.toString();
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            return rlist.retainAll(c);
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            return rlist.removeAll(c);
+        }
+
+        public boolean containsAll(Collection<?> c) {
+            return rlist.containsAll(c);
+        }
+
+        public boolean isEmpty() {
+            return rlist.isEmpty();
+        }
+
+        public Stream<E> parallelStream() {
+            return rlist.parallelStream();
+        }
+
+        public Stream<E> stream() {
+            return rlist.stream();
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            return rlist.removeIf(filter);
+        }
+
+        public <T> T[] toArray(IntFunction<T[]> generator) {
+            return rlist.toArray(generator);
+        }
+
+        public void forEach(Consumer<? super E> action) {
+            rlist.forEach(action);
+        }
+
+        public Iterator<E> iterator() {
+            return rlist.iterator();
+        }
+
+        public int hashCode() {
+            return rlist.hashCode();
+        }
+
+        public boolean equals(Object o) {
+            return rlist.equals(o);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return rlist.subList(fromIndex, toIndex);
+        }
+
+        public ListIterator<E> listIterator() {
+            return rlist.listIterator();
+        }
+
+        public void sort(Comparator<? super E> c) {
+            rlist.sort(c);
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            rlist.replaceAll(operator);
+        }
+
+        public LinkedList<E> reversed() {
+            return list;
+        }
+
+        public Spliterator<E> spliterator() {
+            return rlist.spliterator();
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return rlist.toArray(a);
+        }
+
+        public Object[] toArray() {
+            return rlist.toArray();
+        }
+
+        public Iterator<E> descendingIterator() {
+            return rdeque.descendingIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            return rlist.listIterator(index);
+        }
+
+        public boolean removeLastOccurrence(Object o) {
+            return rdeque.removeLastOccurrence(o);
+        }
+
+        public boolean removeFirstOccurrence(Object o) {
+            return rdeque.removeFirstOccurrence(o);
+        }
+
+        public E pop() {
+            return rdeque.pop();
+        }
+
+        public void push(E e) {
+            rdeque.push(e);
+        }
+
+        public E pollLast() {
+            return rdeque.pollLast();
+        }
+
+        public E pollFirst() {
+            return rdeque.pollFirst();
+        }
+
+        public E peekLast() {
+            return rdeque.peekLast();
+        }
+
+        public E peekFirst() {
+            return rdeque.peekFirst();
+        }
+
+        public boolean offerLast(E e) {
+            return rdeque.offerLast(e);
+        }
+
+        public boolean offerFirst(E e) {
+            return rdeque.offerFirst(e);
+        }
+
+        public boolean offer(E e) {
+            return rdeque.offer(e);
+        }
+
+        public E remove() {
+            return rdeque.remove();
+        }
+
+        public E poll() {
+            return rdeque.poll();
+        }
+
+        public E element() {
+            return rdeque.element();
+        }
+
+        public E peek() {
+            return rdeque.peek();
+        }
+
+        public int lastIndexOf(Object o) {
+            return rlist.lastIndexOf(o);
+        }
+
+        public int indexOf(Object o) {
+            return rlist.indexOf(o);
+        }
+
+        public E remove(int index) {
+            return rlist.remove(index);
+        }
+
+        public void add(int index, E element) {
+            rlist.add(index, element);
+        }
+
+        public E set(int index, E element) {
+            return rlist.set(index, element);
+        }
+
+        public E get(int index) {
+            return rlist.get(index);
+        }
+
+        public void clear() {
+            rlist.clear();
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            return rlist.addAll(index, c);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return rlist.addAll(c);
+        }
+
+        public boolean remove(Object o) {
+            return rlist.remove(o);
+        }
+
+        public boolean add(E e) {
+            return rlist.add(e);
+        }
+
+        public int size() {
+            return rlist.size();
+        }
+
+        public boolean contains(Object o) {
+            return rlist.contains(o);
+        }
+
+        public void addLast(E e) {
+            rdeque.addLast(e);
+        }
+
+        public void addFirst(E e) {
+            rdeque.addFirst(e);
+        }
+
+        public E removeLast() {
+            return rdeque.removeLast();
+        }
+
+        public E removeFirst() {
+            return rdeque.removeFirst();
+        }
+
+        public E getLast() {
+            return rdeque.getLast();
+        }
+
+        public E getFirst() {
+            return rdeque.getFirst();
+        }
+
+        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+            throw new java.io.InvalidObjectException("not serializable");
+        }
+
+        public void writeExternal(ObjectOutput out) throws IOException {
+            throw new java.io.InvalidObjectException("not serializable");
+        }
+    }
+}
diff --git a/android-35/java/util/List.java b/android-35/java/util/List.java
new file mode 100644
index 0000000..ad5f4ee
--- /dev/null
+++ b/android-35/java/util/List.java
@@ -0,0 +1,1214 @@
+/*
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.UnaryOperator;
+
+// Android-removed: removed link to collections framework docs
+/**
+ * An ordered collection, where the user has precise control over where in the
+ * list each element is inserted.  The user can access elements by their integer
+ * index (position in the list), and search for elements in the list.<p>
+ *
+ * Unlike sets, lists typically allow duplicate elements.  More formally,
+ * lists typically allow pairs of elements {@code e1} and {@code e2}
+ * such that {@code e1.equals(e2)}, and they typically allow multiple
+ * null elements if they allow null elements at all.  It is not inconceivable
+ * that someone might wish to implement a list that prohibits duplicates, by
+ * throwing runtime exceptions when the user attempts to insert them, but we
+ * expect this usage to be rare.<p>
+ *
+ * The {@code List} interface places additional stipulations, beyond those
+ * specified in the {@code Collection} interface, on the contracts of the
+ * {@code iterator}, {@code add}, {@code remove}, {@code equals}, and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.<p>
+ *
+ * The {@code List} interface provides four methods for positional (indexed)
+ * access to list elements.  Lists (like Java arrays) are zero based.  Note
+ * that these operations may execute in time proportional to the index value
+ * for some implementations (the {@code LinkedList} class, for
+ * example). Thus, iterating over the elements in a list is typically
+ * preferable to indexing through it if the caller does not know the
+ * implementation.<p>
+ *
+ * The {@code List} interface provides a special iterator, called a
+ * {@code ListIterator}, that allows element insertion and replacement, and
+ * bidirectional access in addition to the normal operations that the
+ * {@code Iterator} interface provides.  A method is provided to obtain a
+ * list iterator that starts at a specified position in the list.<p>
+ *
+ * The {@code List} interface provides two methods to search for a specified
+ * object.  From a performance standpoint, these methods should be used with
+ * caution.  In many implementations they will perform costly linear
+ * searches.<p>
+ *
+ * The {@code List} interface provides two methods to efficiently insert and
+ * remove multiple elements at an arbitrary point in the list.<p>
+ *
+ * Note: While it is permissible for lists to contain themselves as elements,
+ * extreme caution is advised: the {@code equals} and {@code hashCode}
+ * methods are no longer well defined on such a list.
+ *
+ * <p>Some list implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the list may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="unmodifiable">Unmodifiable Lists</a></h2>
+ * <p>The {@link List#of(Object...) List.of} and
+ * {@link List#copyOf List.copyOf} static factory methods
+ * provide a convenient way to create unmodifiable lists. The {@code List}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
+ * be added, removed, or replaced. Calling any mutator method on the List
+ * will always cause {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable,
+ * this may cause the List's contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>The order of elements in the list is the same as the order of the
+ * provided arguments, or of the elements in the provided array.
+ * <li>The lists and their {@link #subList(int, int) subList} views implement the
+ * {@link RandomAccess} interface.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions about the
+ * identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see Set
+ * @see ArrayList
+ * @see LinkedList
+ * @see Vector
+ * @see Arrays#asList(Object[])
+ * @see Collections#nCopies(int, Object)
+ * @see Collections#EMPTY_LIST
+ * @see AbstractList
+ * @see AbstractSequentialList
+ * @since 1.2
+ */
+
+public interface List<E> extends SequencedCollection<E>, Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this list.  If this list contains
+     * more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this list
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must
+     * allocate a new array even if this list is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in proper
+     *         sequence
+     * @see Arrays#asList(Object[])
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If the list fits in the specified array with room to spare (i.e.,
+     * the array has more elements than the list), the element in the array
+     * immediately following the end of the list is set to {@code null}.
+     * (This is useful in determining the length of the list <i>only</i> if
+     * the caller knows that the list does not contain any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre>{@code
+     *     String[] y = x.toArray(new String[0]);
+     * }</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    boolean add(E e);
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present (optional operation).  If this list does not contain
+     * the element, it is unchanged.  More formally, removes the element with
+     * the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list changed
+     * as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Modification Operations
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param  c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator (optional operation).  The behavior of this
+     * operation is undefined if the specified collection is modified while
+     * the operation is in progress.  (Note that this will occur if the
+     * specified collection is this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    boolean addAll(int index, Collection<? extends E> c);
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection (optional operation).
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this list all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Replaces each element of this list with the result of applying the
+     * operator to that element.  Errors or runtime exceptions thrown by
+     * the operator are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code list}:
+     * <pre>{@code
+     *     final ListIterator<E> li = list.listIterator();
+     *     while (li.hasNext()) {
+     *         li.set(operator.apply(li.next()));
+     *     }
+     * }</pre>
+     *
+     * If the list's list-iterator does not support the {@code set} operation
+     * then an {@code UnsupportedOperationException} will be thrown when
+     * replacing the first element.
+     *
+     * @param operator the operator to apply to each element
+     * @throws UnsupportedOperationException if this list is unmodifiable.
+     *         Implementations may throw this exception if an element
+     *         cannot be replaced or if, in general, modification is not
+     *         supported
+     * @throws NullPointerException if the specified operator is null or
+     *         if the operator result is a null value and this list does
+     *         not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final ListIterator<E> li = this.listIterator();
+        while (li.hasNext()) {
+            li.set(operator.apply(li.next()));
+        }
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts this list according to the order induced by the specified
+     * {@link Comparator}.
+     *
+     * <p>All elements in this list must be <i>mutually comparable</i> using the
+     * specified comparator (that is, {@code c.compare(e1, e2)} must not throw
+     * a {@code ClassCastException} for any elements {@code e1} and {@code e2}
+     * in the list).
+     *
+     * <p>If the specified comparator is {@code null} then all elements in this
+     * list must implement the {@link Comparable} interface and the elements'
+     * {@linkplain Comparable natural ordering} should be used.
+     *
+     * <p>This list must be modifiable, but need not be resizable.
+     *
+     * <p>For apps running on and targeting Android versions greater than
+     * Nougat (API level {@code > 25}), {@link Collections#sort(List)}
+     * delegates to this method. Such apps must not call
+     * {@link Collections#sort(List)} from this method. Instead, prefer
+     * not overriding this method at all. If you must override it, consider
+     * this implementation:
+     * <pre>
+     * &#064;Override
+     * public void sort(Comparator&lt;? super E&gt; c) {
+     *   Object[] elements = toArray();
+     *   Arrays.sort(elements, c);
+     *   ListIterator&lt;E&gt; iterator = (ListIterator&lt;Object&gt;) listIterator();
+     *   for (Object element : elements) {
+     *     iterator.next();
+     *     iterator.set((E) element);
+     *   }
+     * }
+     * </pre>
+     *
+     * @implSpec
+     * The default implementation obtains an array containing all elements in
+     * this list, sorts the array, and iterates over this list resetting each
+     * element from the corresponding position in the array. (This avoids the
+     * n<sup>2</sup> log(n) performance that would result from attempting
+     * to sort a linked list in place.)
+     *
+     * @implNote
+     * This implementation is a stable, adaptive, iterative mergesort that
+     * requires far fewer than n lg(n) comparisons when the input array is
+     * partially sorted, while offering the performance of a traditional
+     * mergesort when the input array is randomly ordered.  If the input array
+     * is nearly sorted, the implementation requires approximately n
+     * comparisons.  Temporary storage requirements vary from a small constant
+     * for nearly sorted input arrays to n/2 object references for randomly
+     * ordered input arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param c the {@code Comparator} used to compare list elements.
+     *          A {@code null} value indicates that the elements'
+     *          {@linkplain Comparable natural ordering} should be used
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator
+     * @throws UnsupportedOperationException if the list's list-iterator does
+     *         not support the {@code set} operation
+     * @throws IllegalArgumentException
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     *         if the comparator is found to violate the {@link Comparator}
+     *         contract
+     * @since 1.8
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    default void sort(Comparator<? super E> c) {
+        Object[] a = this.toArray();
+        Arrays.sort(a, (Comparator) c);
+        ListIterator<E> i = this.listIterator();
+        for (Object e : a) {
+            i.next();
+            i.set((E) e);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.  This
+     * definition ensures that the equals method works properly across
+     * different implementations of the {@code List} interface.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this list.  The hash code of a list
+     * is defined to be the result of the following calculation:
+     * <pre>{@code
+     *     int hashCode = 1;
+     *     for (E e : list)
+     *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+     * }</pre>
+     * This ensures that {@code list1.equals(list2)} implies that
+     * {@code list1.hashCode()==list2.hashCode()} for any two lists,
+     * {@code list1} and {@code list2}, as required by the general
+     * contract of {@link Object#hashCode}.
+     *
+     * @return the hash code value for this list
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E get(int index);
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E set(int index, E element);
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    void add(int index, E element);
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E remove(int index);
+
+
+    // Search Operations
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int indexOf(Object o);
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int lastIndexOf(Object o);
+
+
+    // List Iterators
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     */
+    ListIterator<E> listIterator();
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * @param index index of the first element to be returned from the
+     *        list iterator (by a call to {@link ListIterator#next next})
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence), starting at the specified position in the list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    ListIterator<E> listIterator(int index);
+
+    // View
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations supported
+     * by this list.<p>
+     *
+     * This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>{@code
+     *      list.subList(from, to).clear();
+     * }</pre>
+     * Similar idioms may be constructed for {@code indexOf} and
+     * {@code lastIndexOf}, and all of the algorithms in the
+     * {@code Collections} class can be applied to a subList.<p>
+     *
+     * The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException for an illegal endpoint index value
+     *         ({@code fromIndex < 0 || toIndex > size ||
+     *         fromIndex > toIndex})
+     */
+    List<E> subList(int fromIndex, int toIndex);
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Implementations should document the
+     * reporting of additional characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * spliterator as follows:
+     * <ul>
+     * <li>If the list is an instance of {@link RandomAccess} then the default
+     *     implementation creates a spliterator that traverses elements by
+     *     invoking the method {@link List#get}.  If such invocation results or
+     *     would result in an {@code IndexOutOfBoundsException} then the
+     *     spliterator will <em>fail-fast</em> and throw a
+     *     {@code ConcurrentModificationException}.
+     *     If the list is also an instance of {@link AbstractList} then the
+     *     spliterator will use the list's {@link AbstractList#modCount modCount}
+     *     field to provide additional <em>fail-fast</em> behavior.
+     * <li>Otherwise, the default implementation creates a spliterator from the
+     *     list's {@code Iterator}.  The spliterator inherits the
+     *     <em>fail-fast</em> of the list's iterator.
+     * </ul>
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        if (this instanceof RandomAccess) {
+            return new AbstractList.RandomAccessSpliterator<>(this);
+        } else {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+    }
+
+    // ========== SequencedCollection ==========
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface calls {@code add(0, e)}.
+     *
+     * @throws NullPointerException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default void addFirst(E e) {
+        this.add(0, e);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface calls {@code add(e)}.
+     *
+     * @throws NullPointerException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default void addLast(E e) {
+        this.add(e);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this List is not empty, the implementation in this interface returns the result
+     * of calling {@code get(0)}. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    default E getFirst() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.get(0);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this List is not empty, the implementation in this interface returns the result
+     * of calling {@code get(size() - 1)}. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    default E getLast() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.get(this.size() - 1);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this List is not empty, the implementation in this interface returns the result
+     * of calling {@code remove(0)}. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeFirst() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.remove(0);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this List is not empty, the implementation in this interface returns the result
+     * of calling {@code remove(size() - 1)}. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeLast() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.remove(this.size() - 1);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns a reverse-ordered List
+     * view. The {@code reversed()} method of the view returns a reference
+     * to this List. Other operations on the view are implemented via calls to
+     * public methods on this List. The exact relationship between calls on the
+     * view and calls on this List is unspecified. However, order-sensitive
+     * operations generally delegate to the appropriate method with the opposite
+     * orientation. For example, calling {@code getFirst} on the view results in
+     * a call to {@code getLast} on this List.
+     *
+     * @return a reverse-ordered view of this collection, as a {@code List}
+     * @since 21
+     */
+    default List<E> reversed() {
+        return ReverseOrderListView.of(this, true); // we must assume it's modifiable
+    }
+
+    // ========== static methods ==========
+
+    /**
+     * Returns an unmodifiable list containing zero elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @return an empty {@code List}
+     *
+     * @since 9
+     */
+    @SuppressWarnings("unchecked")
+    static <E> List<E> of() {
+        return (List<E>) ImmutableCollections.EMPTY_LIST;
+    }
+
+    /**
+     * Returns an unmodifiable list containing one element.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the single element
+     * @return a {@code List} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1) {
+        return new ImmutableCollections.List12<>(e1);
+    }
+
+    /**
+     * Returns an unmodifiable list containing two elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2) {
+        return new ImmutableCollections.List12<>(e1, e2);
+    }
+
+    /**
+     * Returns an unmodifiable list containing three elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3);
+    }
+
+    /**
+     * Returns an unmodifiable list containing four elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an unmodifiable list containing five elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an unmodifiable list containing six elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+                                                         e6);
+    }
+
+    /**
+     * Returns an unmodifiable list containing seven elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+                                                         e6, e7);
+    }
+
+    /**
+     * Returns an unmodifiable list containing eight elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+                                                         e6, e7, e8);
+    }
+
+    /**
+     * Returns an unmodifiable list containing nine elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+                                                         e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an unmodifiable list containing ten elements.
+     *
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+                                                         e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an unmodifiable list containing an arbitrary number of elements.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting list will be the component type of the array, and the size of
+     * the list will be equal to the length of the array. To create a list with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     List<String[]> list = List.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link List#of(Object) List.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param elements the elements to be contained in the list
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> List<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                @SuppressWarnings("unchecked")
+                var list = (List<E>) ImmutableCollections.EMPTY_LIST;
+                return list;
+            case 1:
+                return new ImmutableCollections.List12<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.List12<>(elements[0], elements[1]);
+            default:
+                return ImmutableCollections.listFromArray(elements);
+        }
+    }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable List</a> containing the elements of
+     * the given Collection, in its iteration order. The given Collection must not be null,
+     * and it must not contain any null elements. If the given Collection is subsequently
+     * modified, the returned List will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Collection is an <a href="#unmodifiable">unmodifiable List</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param coll a {@code Collection} from which elements are drawn, must be non-null
+     * @return a {@code List} containing the elements of the given {@code Collection}
+     * @throws NullPointerException if coll is null, or if it contains any nulls
+     * @since 10
+     */
+    static <E> List<E> copyOf(Collection<? extends E> coll) {
+        return ImmutableCollections.listCopy(coll);
+    }
+}
diff --git a/android-35/java/util/ListIterator.java b/android-35/java/util/ListIterator.java
new file mode 100644
index 0000000..365daf0
--- /dev/null
+++ b/android-35/java/util/ListIterator.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An iterator for lists that allows the programmer
+ * to traverse the list in either direction, modify
+ * the list during iteration, and obtain the iterator's
+ * current position in the list. A {@code ListIterator}
+ * has no current element; its <I>cursor position</I> always
+ * lies between the element that would be returned by a call
+ * to {@code previous()} and the element that would be
+ * returned by a call to {@code next()}.
+ * An iterator for a list of length {@code n} has {@code n+1} possible
+ * cursor positions, as illustrated by the carets ({@code ^}) below:
+ * <PRE>
+ *                      Element(0)   Element(1)   Element(2)   ... Element(n-1)
+ * cursor positions:  ^            ^            ^            ^                  ^
+ * </PRE>
+ * Note that the {@link #remove} and {@link #set(Object)} methods are
+ * <i>not</i> defined in terms of the cursor position;  they are defined to
+ * operate on the last element returned by a call to {@link #next} or
+ * {@link #previous()}.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see List
+ * @see Iterator
+ * @see Enumeration
+ * @see List#listIterator()
+ * @since   1.2
+ */
+public interface ListIterator<E> extends Iterator<E> {
+    // Query Operations
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the forward direction. (In other words,
+     * returns {@code true} if {@link #next} would return an element rather
+     * than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the forward direction
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the list and advances the cursor position.
+     * This method may be called repeatedly to iterate through the list,
+     * or intermixed with calls to {@link #previous} to go back and forth.
+     * (Note that alternating calls to {@code next} and {@code previous}
+     * will return the same element repeatedly.)
+     *
+     * @return the next element in the list
+     * @throws NoSuchElementException if the iteration has no next element
+     */
+    E next();
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the reverse direction.  (In other words,
+     * returns {@code true} if {@link #previous} would return an element
+     * rather than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the reverse direction
+     */
+    boolean hasPrevious();
+
+    /**
+     * Returns the previous element in the list and moves the cursor
+     * position backwards.  This method may be called repeatedly to
+     * iterate through the list backwards, or intermixed with calls to
+     * {@link #next} to go back and forth.  (Note that alternating calls
+     * to {@code next} and {@code previous} will return the same
+     * element repeatedly.)
+     *
+     * @return the previous element in the list
+     * @throws NoSuchElementException if the iteration has no previous
+     *         element
+     */
+    E previous();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #next}. (Returns list size if the list
+     * iterator is at the end of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code next}, or list size if the list
+     *         iterator is at the end of the list
+     */
+    int nextIndex();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #previous}. (Returns -1 if the list
+     * iterator is at the beginning of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code previous}, or -1 if the list
+     *         iterator is at the beginning of the list
+     */
+    int previousIndex();
+
+
+    // Modification Operations
+
+    /**
+     * Removes from the list the last element that was returned by {@link
+     * #next} or {@link #previous} (optional operation).  This call can
+     * only be made once per call to {@code next} or {@code previous}.
+     * It can be made only if {@link #add} has not been
+     * called after the last call to {@code next} or {@code previous}.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this list iterator
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void remove();
+
+    /**
+     * Replaces the last element returned by {@link #next} or
+     * {@link #previous} with the specified element (optional operation).
+     * This call can be made only if neither {@link #remove} nor {@link
+     * #add} have been called after the last call to {@code next} or
+     * {@code previous}.
+     *
+     * @param e the element with which to replace the last element returned by
+     *          {@code next} or {@code previous}
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of the specified
+     *         element prevents it from being added to this list
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void set(E e);
+
+    /**
+     * Inserts the specified element into the list (optional operation).
+     * The element is inserted immediately before the element that
+     * would be returned by {@link #next}, if any, and after the element
+     * that would be returned by {@link #previous}, if any.  (If the
+     * list contains no elements, the new element becomes the sole element
+     * on the list.)  The new element is inserted before the implicit
+     * cursor: a subsequent call to {@code next} would be unaffected, and a
+     * subsequent call to {@code previous} would return the new element.
+     * (This call increases by one the value that would be returned by a
+     * call to {@code nextIndex} or {@code previousIndex}.)
+     *
+     * @param e the element to insert
+     * @throws UnsupportedOperationException if the {@code add} method is
+     *         not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of this element
+     *         prevents it from being added to this list
+     */
+    void add(E e);
+}
diff --git a/android-35/java/util/ListResourceBundle.java b/android-35/java/util/ListResourceBundle.java
new file mode 100644
index 0000000..053d70b
--- /dev/null
+++ b/android-35/java/util/ListResourceBundle.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * {@code ListResourceBundle} is an abstract subclass of
+ * {@code ResourceBundle} that manages resources for a locale
+ * in a convenient and easy to use list. See {@code ResourceBundle} for
+ * more information about resource bundles in general.
+ *
+ * <P>
+ * Subclasses must override {@code getContents} and provide an array,
+ * where each item in the array is a pair of objects.
+ * The first element of each pair is the key, which must be a
+ * {@code String}, and the second element is the value associated with
+ * that key.
+ *
+ * <p>
+ * The following <a id="sample">example</a> shows two members of a resource
+ * bundle family with the base name "MyResources".
+ * "MyResources" is the default member of the bundle family, and
+ * "MyResources_fr" is the French member.
+ * These members are based on {@code ListResourceBundle}
+ * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows
+ * how you can add a bundle to this family that's based on a properties file).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ *
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "My Disk"},                         // sample disk name
+ *             {"s4", "no files"},                        // first ChoiceFormat choice
+ *             {"s5", "one file"},                        // second ChoiceFormat choice
+ *             {"s6", "{0,number} files"},                // third ChoiceFormat choice
+ *             {"s7", "3 Mar 96"},                        // sample date
+ *             {"s8", new Dimension(1,5)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ *
+ * public class MyResources_fr extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "Mon disque"},                      // sample disk name
+ *             {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
+ *             {"s5", "contient un fichier"},             // second ChoiceFormat choice
+ *             {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
+ *             {"s7", "3 mars 1996"},                     // sample date
+ *             {"s8", new Dimension(1,3)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the methods in this class are thread-safe.
+ *
+ * @see ResourceBundle
+ * @see PropertyResourceBundle
+ * @since 1.1
+ */
+public abstract class ListResourceBundle extends ResourceBundle {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ListResourceBundle() {
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public final Object handleGetObject(String key) {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key); // this class ignores locales
+    }
+
+    /**
+     * Returns an {@code Enumeration} of the keys contained in
+     * this {@code ResourceBundle} and its parent bundles.
+     *
+     * @return an {@code Enumeration} of the keys contained in
+     *         this {@code ResourceBundle} and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a {@code Set} of the keys contained
+     * <em>only</em> in this {@code ResourceBundle}.
+     *
+     * @return a {@code Set} of the keys contained only in this
+     *         {@code ResourceBundle}
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        if (lookup == null) {
+            loadLookup();
+        }
+        return lookup.keySet();
+    }
+
+    /**
+     * Returns an array in which each item is a pair of objects in an
+     * {@code Object} array. The first element of each pair is
+     * the key, which must be a {@code String}, and the second
+     * element is the value associated with that key.  See the class
+     * description for details.
+     *
+     * @return an array of an {@code Object} array representing a
+     * key-value pair.
+     */
+    protected abstract Object[][] getContents();
+
+    // ==================privates====================
+
+    /**
+     * We lazily load the lookup hashtable.  This function does the
+     * loading.
+     */
+    private synchronized void loadLookup() {
+        if (lookup != null)
+            return;
+
+        Object[][] contents = getContents();
+        HashMap<String,Object> temp = new HashMap<>(contents.length);
+        for (Object[] content : contents) {
+            // key must be non-null String, value must be non-null
+            String key = (String) content[0];
+            Object value = content[1];
+            if (key == null || value == null) {
+                throw new NullPointerException();
+            }
+            temp.put(key, value);
+        }
+        lookup = temp;
+    }
+
+    private volatile Map<String,Object> lookup;
+}
diff --git a/android-35/java/util/Locale.java b/android-35/java/util/Locale.java
new file mode 100644
index 0000000..f2c4f5d
--- /dev/null
+++ b/android-35/java/util/Locale.java
@@ -0,0 +1,4001 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import com.android.icu.util.LocaleNative;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import libcore.icu.ICU;
+
+import sun.util.locale.BaseLocale;
+import sun.util.locale.InternalLocaleBuilder;
+import sun.util.locale.LanguageTag;
+import sun.util.locale.LocaleExtensions;
+import sun.util.locale.LocaleMatcher;
+import sun.util.locale.LocaleObjectCache;
+import sun.util.locale.LocaleSyntaxException;
+import sun.util.locale.LocaleUtils;
+import sun.util.locale.ParseStatus;
+
+// Android-added: documentation about ICU data & warning of default locale.
+// Android-removed: backwards-compatibility section in "Legacy language codes".
+/**
+ * A {@code Locale} object represents a specific geographical, political,
+ * or cultural region. An operation that requires a {@code Locale} to perform
+ * its task is called <em>locale-sensitive</em> and uses the {@code Locale}
+ * to tailor information for the user. For example, displaying a number
+ * is a locale-sensitive operation&mdash; the number should be formatted
+ * according to the customs and conventions of the user's native country,
+ * region, or culture.
+ *
+ * <p> The {@code Locale} class implements IETF BCP 47 which is composed of
+ * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
+ * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
+ * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
+ * Locale Data Markup Language") BCP 47-compatible extensions for locale data
+ * exchange.
+ *
+ * <p> A {@code Locale} object logically consists of the fields
+ * described below.
+ *
+ * <dl>
+ *   <dt><a id="def_language"><b>language</b></a></dt>
+ *
+ *   <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
+ *   language subtags up to 8 alpha letters (for future enhancements).
+ *   When a language has both an alpha-2 code and an alpha-3 code, the
+ *   alpha-2 code must be used.  You can find a full list of valid
+ *   language codes in the IANA Language Subtag Registry (search for
+ *   "Type: language").  The language field is case insensitive, but
+ *   {@code Locale} always canonicalizes to lower case.</dd>
+ *
+ *   <dd>Well-formed language values have the form
+ *   <code>[a-zA-Z]{2,8}</code>.  Note that this is not the full
+ *   BCP47 language production, since it excludes extlang.  They are
+ *   not needed since modern three-letter language codes replace
+ *   them.</dd>
+ *
+ *   <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd>
+ *
+ *   <dt><a id="def_script"><b>script</b></a></dt>
+ *
+ *   <dd>ISO 15924 alpha-4 script code.  You can find a full list of
+ *   valid script codes in the IANA Language Subtag Registry (search
+ *   for "Type: script").  The script field is case insensitive, but
+ *   {@code Locale} always canonicalizes to title case (the first
+ *   letter is upper case and the rest of the letters are lower
+ *   case).</dd>
+ *
+ *   <dd>Well-formed script values have the form
+ *   <code>[a-zA-Z]{4}</code></dd>
+ *
+ *   <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd>
+ *
+ *   <dt><a id="def_region"><b>country (region)</b></a></dt>
+ *
+ *   <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
+ *   You can find a full list of valid country and region codes in the
+ *   IANA Language Subtag Registry (search for "Type: region").  The
+ *   country (region) field is case insensitive, but
+ *   {@code Locale} always canonicalizes to upper case.</dd>
+ *
+ *   <dd>Well-formed country/region values have
+ *   the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd>
+ *
+ *   <dd>Example: "US" (United States), "FR" (France), "029"
+ *   (Caribbean)</dd>
+ *
+ *   <dt><a id="def_variant"><b>variant</b></a></dt>
+ *
+ *   <dd>Any arbitrary value used to indicate a variation of a
+ *   {@code Locale}.  Where there are two or more variant values
+ *   each indicating its own semantics, these values should be ordered
+ *   by importance, with most important first, separated by
+ *   underscore('_').  The variant field is case sensitive.</dd>
+ *
+ *   <dd>Note: IETF BCP 47 places syntactic restrictions on variant
+ *   subtags.  Also BCP 47 subtags are strictly used to indicate
+ *   additional variations that define a language or its dialects that
+ *   are not covered by any combinations of language, script and
+ *   region subtags.  You can find a full list of valid variant codes
+ *   in the IANA Language Subtag Registry (search for "Type: variant").
+ *
+ *   <p>However, the variant field in {@code Locale} has
+ *   historically been used for any kind of variation, not just
+ *   language variations.  For example, some supported variants
+ *   available in Java SE Runtime Environments indicate alternative
+ *   cultural behaviors such as calendar type or number script.  In
+ *   BCP 47 this kind of information, which does not identify the
+ *   language, is supported by extension subtags or private use
+ *   subtags.</dd>
+ *
+ *   <dd>Well-formed variant values have the form <code>SUBTAG
+ *   (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
+ *   [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
+ *   uses hyphen ('-') as a delimiter, this is more lenient).</dd>
+ *
+ *   <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd>
+ *
+ *   <dt><a id="def_extensions"><b>extensions</b></a></dt>
+ *
+ *   <dd>A map from single character keys to string values, indicating
+ *   extensions apart from language identification.  The extensions in
+ *   {@code Locale} implement the semantics and syntax of BCP 47
+ *   extension subtags and private use subtags. The extensions are
+ *   case insensitive, but {@code Locale} canonicalizes all
+ *   extension keys and values to lower case. Note that extensions
+ *   cannot have empty values.</dd>
+ *
+ *   <dd>Well-formed keys are single characters from the set
+ *   {@code [0-9a-zA-Z]}.  Well-formed values have the form
+ *   {@code SUBTAG ('-' SUBTAG)*} where for the key 'x'
+ *   <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
+ *   <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
+ *   single-character subtags).</dd>
+ *
+ *   <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
+ *   key="x"/value="java-1-7"</dd>
+ * </dl>
+ *
+ * <b>Note:</b> Although BCP 47 requires field values to be registered
+ * in the IANA Language Subtag Registry, the {@code Locale} class
+ * does not provide any validation features.  The {@code Builder}
+ * only checks if an individual field satisfies the syntactic
+ * requirement (is well-formed), but does not validate the value
+ * itself.  See {@link Builder} for details.
+ *
+ * <h2><a id="def_locale_extension">Unicode locale/language extension</a></h2>
+ *
+ * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
+ * attributes and keywords to override or refine the default behavior
+ * associated with a locale.  A keyword is represented by a pair of
+ * key and type.  For example, "nu-thai" indicates that Thai local
+ * digits (value:"thai") should be used for formatting numbers
+ * (key:"nu").
+ *
+ * <p>The keywords are mapped to a BCP 47 extension value using the
+ * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}).  The above
+ * example, "nu-thai", becomes the extension "u-nu-thai".
+ *
+ * <p>Thus, when a {@code Locale} object contains Unicode locale
+ * attributes and keywords,
+ * {@code getExtension(UNICODE_LOCALE_EXTENSION)} will return a
+ * String representing this information, for example, "nu-thai".  The
+ * {@code Locale} class also provides {@link
+ * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
+ * {@link #getUnicodeLocaleType} which allow you to access Unicode
+ * locale attributes and key/type pairs directly.  When represented as
+ * a string, the Unicode Locale Extension lists attributes
+ * alphabetically, followed by key/type sequences with keys listed
+ * alphabetically (the order of subtags comprising a key's type is
+ * fixed when the type is defined)
+ *
+ * <p>A well-formed locale key has the form
+ * <code>[0-9a-zA-Z]{2}</code>.  A well-formed locale type has the
+ * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
+ * can be empty, or a series of subtags 3-8 alphanums in length).  A
+ * well-formed locale attribute has the form
+ * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
+ * form as a locale type subtag).
+ *
+ * <p>The Unicode locale extension specifies optional behavior in
+ * locale-sensitive services.  Although the LDML specification defines
+ * various keys and values, actual locale-sensitive service
+ * implementations in a Java Runtime Environment might not support any
+ * particular Unicode locale attributes or key/type pairs.
+ *
+ * <h3>Creating a Locale</h3>
+ *
+ * <p>There are several different ways to create a {@code Locale}
+ * object.
+ *
+ * <h4>Builder</h4>
+ *
+ * <p>Using {@link Builder} you can construct a {@code Locale} object
+ * that conforms to BCP 47 syntax.
+ *
+ * <h4>Constructors</h4>
+ *
+ * <p>The {@code Locale} class provides three constructors:
+ * <blockquote>
+ * <pre>
+ *     {@link #Locale(String language)}
+ *     {@link #Locale(String language, String country)}
+ *     {@link #Locale(String language, String country, String variant)}
+ * </pre>
+ * </blockquote>
+ * These constructors allow you to create a {@code Locale} object
+ * with language, country and variant, but you cannot specify
+ * script or extensions.
+ *
+ * <h4>Factory Methods</h4>
+ *
+ * <p>The method {@link #forLanguageTag} creates a {@code Locale}
+ * object for a well-formed BCP 47 language tag.
+ *
+ * <h4>Locale Constants</h4>
+ *
+ * <p>The {@code Locale} class provides a number of convenient constants
+ * that you can use to create {@code Locale} objects for commonly used
+ * locales. For example, the following creates a {@code Locale} object
+ * for the United States:
+ * <blockquote>
+ * <pre>
+ *     Locale.US
+ * </pre>
+ * </blockquote>
+ *
+ * <h3><a id="LocaleMatching">Locale Matching</a></h3>
+ *
+ * <p>If an application or a system is internationalized and provides localized
+ * resources for multiple locales, it sometimes needs to find one or more
+ * locales (or language tags) which meet each user's specific preferences. Note
+ * that a term "language tag" is used interchangeably with "locale" in this
+ * locale matching documentation.
+ *
+ * <p>In order to do matching a user's preferred locales to a set of language
+ * tags, <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+ * Language Tags</a> defines two mechanisms: filtering and lookup.
+ * <em>Filtering</em> is used to get all matching locales, whereas
+ * <em>lookup</em> is to choose the best matching locale.
+ * Matching is done case-insensitively. These matching mechanisms are described
+ * in the following sections.
+ *
+ * <p>A user's preference is called a <em>Language Priority List</em> and is
+ * expressed as a list of language ranges. There are syntactically two types of
+ * language ranges: basic and extended. See
+ * {@link Locale.LanguageRange Locale.LanguageRange} for details.
+ *
+ * <h4>Filtering</h4>
+ *
+ * <p>The filtering operation returns all matching language tags. It is defined
+ * in RFC 4647 as follows:
+ * "In filtering, each language range represents the least specific language
+ * tag (that is, the language tag with fewest number of subtags) that is an
+ * acceptable match. All of the language tags in the matching set of tags will
+ * have an equal or greater number of subtags than the language range. Every
+ * non-wildcard subtag in the language range will appear in every one of the
+ * matching language tags."
+ *
+ * <p>There are two types of filtering: filtering for basic language ranges
+ * (called "basic filtering") and filtering for extended language ranges
+ * (called "extended filtering"). They may return different results by what
+ * kind of language ranges are included in the given Language Priority List.
+ * {@link Locale.FilteringMode} is a parameter to specify how filtering should
+ * be done.
+ *
+ * <h4>Lookup</h4>
+ *
+ * <p>The lookup operation returns the best matching language tags. It is
+ * defined in RFC 4647 as follows:
+ * "By contrast with filtering, each language range represents the most
+ * specific tag that is an acceptable match.  The first matching tag found,
+ * according to the user's priority, is considered the closest match and is the
+ * item returned."
+ *
+ * <p>For example, if a Language Priority List consists of two language ranges,
+ * {@code "zh-Hant-TW"} and {@code "en-US"}, in prioritized order, lookup
+ * method progressively searches the language tags below in order to find the
+ * best matching language tag.
+ * <blockquote>
+ * <pre>
+ *    1. zh-Hant-TW
+ *    2. zh-Hant
+ *    3. zh
+ *    4. en-US
+ *    5. en
+ * </pre>
+ * </blockquote>
+ * If there is a language tag which matches completely to a language range
+ * above, the language tag is returned.
+ *
+ * <p>{@code "*"} is the special language range, and it is ignored in lookup.
+ *
+ * <p>If multiple language tags match as a result of the subtag {@code '*'}
+ * included in a language range, the first matching language tag returned by
+ * an {@link Iterator} over a {@link Collection} of language tags is treated as
+ * the best matching one.
+ *
+ * <h3>Use of Locale</h3>
+ *
+ * <p>Once you've created a {@code Locale} you can query it for information
+ * about itself. Use {@code getCountry} to get the country (or region)
+ * code and {@code getLanguage} to get the language code.
+ * You can use {@code getDisplayCountry} to get the
+ * name of the country suitable for displaying to the user. Similarly,
+ * you can use {@code getDisplayLanguage} to get the name of
+ * the language suitable for displaying to the user. Interestingly,
+ * the {@code getDisplayXXX} methods are themselves locale-sensitive
+ * and have two versions: one that uses the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale and one
+ * that uses the locale specified as an argument.
+ *
+ * <p>The Java Platform provides a number of classes that perform locale-sensitive
+ * operations. For example, the {@code NumberFormat} class formats
+ * numbers, currency, and percentages in a locale-sensitive manner. Classes
+ * such as {@code NumberFormat} have several convenience methods
+ * for creating a default object of that type. For example, the
+ * {@code NumberFormat} class provides these three convenience methods
+ * for creating a default {@code NumberFormat} object:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance()
+ *     NumberFormat.getCurrencyInstance()
+ *     NumberFormat.getPercentInstance()
+ * </pre>
+ * </blockquote>
+ * Each of these methods has two variants; one with an explicit locale
+ * and one without; the latter uses the default
+ * {@link Locale.Category#FORMAT FORMAT} locale:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance(myLocale)
+ *     NumberFormat.getCurrencyInstance(myLocale)
+ *     NumberFormat.getPercentInstance(myLocale)
+ * </pre>
+ * </blockquote>
+ * A {@code Locale} is the mechanism for identifying the kind of object
+ * ({@code NumberFormat}) that you would like to get. The locale is
+ * <STRONG>just</STRONG> a mechanism for identifying objects,
+ * <STRONG>not</STRONG> a container for the objects themselves.
+ *
+ * <h3>Compatibility</h3>
+ *
+ * <p>In order to maintain compatibility with existing usage, Locale's
+ * constructors retain their behavior prior to the Java Runtime
+ * Environment version 1.7.  The same is largely true for the
+ * {@code toString} method. Thus Locale objects can continue to
+ * be used as they were. In particular, clients who parse the output
+ * of toString into language, country, and variant fields can continue
+ * to do so (although this is strongly discouraged), although the
+ * variant field will have additional information in it if script or
+ * extensions are present.
+ *
+ * <p>In addition, BCP 47 imposes syntax restrictions that are not
+ * imposed by Locale's constructors. This means that conversions
+ * between some Locales and BCP 47 language tags cannot be made without
+ * losing information. Thus {@code toLanguageTag} cannot
+ * represent the state of locales whose language, country, or variant
+ * do not conform to BCP 47.
+ *
+ * <p>Because of these issues, it is recommended that clients migrate
+ * away from constructing non-conforming locales and use the
+ * {@code forLanguageTag} and {@code Locale.Builder} APIs instead.
+ * Clients desiring a string representation of the complete locale can
+ * then always rely on {@code toLanguageTag} for this purpose.
+ *
+ * <h4><a id="special_cases_constructor">Special cases</a></h4>
+ *
+ * <p>For compatibility reasons, two
+ * non-conforming locales are treated as special cases.  These are
+ * <b>{@code ja_JP_JP}</b> and <b>{@code th_TH_TH}</b>. These are ill-formed
+ * in BCP 47 since the variants are too short. To ease migration to BCP 47,
+ * these are treated specially during construction.  These two cases (and only
+ * these) cause a constructor to generate an extension, all other values behave
+ * exactly as they did prior to Java 7.
+ *
+ * <p>Java has used {@code ja_JP_JP} to represent Japanese as used in
+ * Japan together with the Japanese Imperial calendar. This is now
+ * representable using a Unicode locale extension, by specifying the
+ * Unicode locale key {@code ca} (for "calendar") and type
+ * {@code japanese}. When the Locale constructor is called with the
+ * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
+ * automatically added.
+ *
+ * <p>Java has used {@code th_TH_TH} to represent Thai as used in
+ * Thailand together with Thai digits. This is also now representable using
+ * a Unicode locale extension, by specifying the Unicode locale key
+ * {@code nu} (for "number") and value {@code thai}. When the Locale
+ * constructor is called with the arguments "th", "TH", "TH", the
+ * extension "u-nu-thai" is automatically added.
+ *
+ * <h4>Serialization</h4>
+ *
+ * <p>During serialization, writeObject writes all fields to the output
+ * stream, including extensions.
+ *
+ * <p>During deserialization, readResolve adds extensions as described
+ * in <a href="#special_cases_constructor">Special Cases</a>, only
+ * for the two cases th_TH_TH and ja_JP_JP.
+ *
+ * <h4><a id="legacy_language_codes">Legacy language codes</a></h4>
+ *
+ * <p>Locale's constructor has always converted three language codes to
+ * their earlier, obsoleted forms: {@code he} maps to {@code iw},
+ * {@code yi} maps to {@code ji}, and {@code id} maps to
+ * {@code in}. Since Java SE 17, this is no longer the case. Each
+ * language maps to its new form; {@code iw} maps to {@code he}, {@code ji}
+ * maps to {@code yi}, and {@code in} maps to {@code id}.
+ *
+ * <p>The APIs added in 1.7 map between the old and new language codes,
+ * maintaining the mapped codes internal to Locale (so that
+ * {@code getLanguage} and {@code toString} reflect the mapped
+ * code, which depends on the {@code java.locale.useOldISOCodes} system
+ * property), but using the new codes in the BCP 47 language tag APIs (so
+ * that {@code toLanguageTag} reflects the new one). This
+ * preserves the equivalence between Locales no matter which code or
+ * API is used to construct them. Java's default resource bundle
+ * lookup mechanism also implements this mapping, so that resources
+ * can be named using either convention, see {@link ResourceBundle.Control}.
+ *
+ * <h4>Three-letter language/country(region) codes</h4>
+ *
+ * <p>The Locale constructors have always specified that the language
+ * and the country param be two characters in length, although in
+ * practice they have accepted any length.  The specification has now
+ * been relaxed to allow language codes of two to eight characters and
+ * country (region) codes of two to three characters, and in
+ * particular, three-letter language codes and three-digit region
+ * codes as specified in the IANA Language Subtag Registry.  For
+ * compatibility, the implementation still does not impose a length
+ * constraint.
+ *
+ * <a name="locale_data"></a><h4>Locale data</h4>
+ * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using
+ * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported.
+ *
+ * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in
+ * various Android releases:
+ * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+ * <tr><td>Android 1.5 (Cupcake)/Android 1.6 (Donut)/Android 2.0 (Eclair)</td>
+ *     <td>ICU 3.8</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
+ * <tr><td>Android 2.2 (Froyo)</td>
+ *     <td>ICU 4.2</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
+ * <tr><td>Android 2.3 (Gingerbread)/Android 3.0 (Honeycomb)</td>
+ *     <td>ICU 4.4</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
+ * <tr><td>Android 4.0 (Ice Cream Sandwich)</td>
+ *     <td><a href="http://site.icu-project.org/download/46">ICU 4.6</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.1 (Jelly Bean)</td>
+ *     <td><a href="http://site.icu-project.org/download/48">ICU 4.8</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.3 (Jelly Bean MR2)</td>
+ *     <td><a href="http://site.icu-project.org/download/50">ICU 50</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-22-1">CLDR 22.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 4.4 (KitKat)</td>
+ *     <td><a href="http://site.icu-project.org/download/51">ICU 51</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-23">CLDR 23</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 5.0 (Lollipop)</td>
+ *     <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr>
+ * <tr><td>Android 6.0 (Marshmallow)</td>
+ *     <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
+ * <tr><td>Android 7.0 (Nougat)</td>
+ *     <td><a href="http://site.icu-project.org/download/56">ICU 56.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-28">CLDR 28</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode8.0.0/">Unicode 8.0</a></td></tr>
+ * <tr><td>Android 8.0 (Oreo)</td>
+ *     <td><a href="http://site.icu-project.org/download/58">ICU 58.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-30">CLDR 30.0.3</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a></td></tr>
+ * <tr><td>Android 9.0 (Pie)</td>
+ *     <td><a href="http://site.icu-project.org/download/60">ICU 60.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-32">CLDR 32.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode10.0.0/">Unicode 10.0</a></td></tr>
+ * <tr><td>Android 10.0 (Q)</td>
+ *     <td><a href="http://site.icu-project.org/download/63">ICU 63.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-34">CLDR 34</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode11.0.0/">Unicode 11.0</a></td></tr>
+ * </table>
+ *
+ * <a name="default_locale"></a><h4>Be wary of the default locale</h3>
+ * <p>Note that there are many convenience methods that automatically use the default locale, but
+ * using them may lead to subtle bugs.
+ *
+ * <p>The default locale is appropriate for tasks that involve presenting data to the user. In
+ * this case, you want to use the user's date/time formats, number
+ * formats, rules for conversion to lowercase, and so on. In this case, it's safe to use the
+ * convenience methods.
+ *
+ * <p>The default locale is <i>not</i> appropriate for machine-readable output. The best choice
+ * there is usually {@code Locale.US}&nbsp;&ndash; this locale is guaranteed to be available on all
+ * devices, and the fact that it has no surprising special cases and is frequently used (especially
+ * for computer-computer communication) means that it tends to be the most efficient choice too.
+ *
+ * <p>A common mistake is to implicitly use the default locale when producing output meant to be
+ * machine-readable. This tends to work on the developer's test devices (especially because so many
+ * developers use en_US), but fails when run on a device whose user is in a more complex locale.
+ *
+ * <p>For example, if you're formatting integers some locales will use non-ASCII decimal
+ * digits. As another example, if you're formatting floating-point numbers some locales will use
+ * {@code ','} as the decimal point and {@code '.'} for digit grouping. That's correct for
+ * human-readable output, but likely to cause problems if presented to another
+ * computer ({@link Double#parseDouble} can't parse such a number, for example).
+ * You should also be wary of the {@link String#toLowerCase} and
+ * {@link String#toUpperCase} overloads that don't take a {@code Locale}: in Turkey, for example,
+ * the characters {@code 'i'} and {@code 'I'} won't be converted to {@code 'I'} and {@code 'i'}.
+ * This is the correct behavior for Turkish text (such as user input), but inappropriate for, say,
+ * HTTP headers.
+ *
+ * @see Builder
+ * @see ResourceBundle
+ * @see java.text.Format
+ * @see java.text.NumberFormat
+ * @see java.text.Collator
+ * @author Mark Davis
+ * @since 1.1
+ */
+public final class Locale implements Cloneable, Serializable {
+
+    /** Useful constant for language.
+     */
+    public static final Locale ENGLISH;
+
+    /** Useful constant for language.
+     */
+    public static final Locale FRENCH;
+
+    /** Useful constant for language.
+     */
+    public static final Locale GERMAN;
+
+    /** Useful constant for language.
+     */
+    public static final Locale ITALIAN;
+
+    /** Useful constant for language.
+     */
+    public static final Locale JAPANESE;
+
+    /** Useful constant for language.
+     */
+    public static final Locale KOREAN;
+
+    /** Useful constant for language.
+     */
+    public static final Locale CHINESE;
+
+    /** Useful constant for language.
+     */
+    public static final Locale SIMPLIFIED_CHINESE;
+
+    /** Useful constant for language.
+     */
+    public static final Locale TRADITIONAL_CHINESE;
+
+    /** Useful constant for country.
+     */
+    public static final Locale FRANCE;
+
+    /** Useful constant for country.
+     */
+    public static final Locale GERMANY;
+
+    /** Useful constant for country.
+     */
+    public static final Locale ITALY;
+
+    /** Useful constant for country.
+     */
+    public static final Locale JAPAN;
+
+    /** Useful constant for country.
+     */
+    public static final Locale KOREA;
+
+    /** Useful constant for country.
+     */
+    public static final Locale UK;
+
+    /** Useful constant for country.
+     */
+    public static final Locale US;
+
+    /** Useful constant for country.
+     */
+    public static final Locale CANADA;
+
+    /** Useful constant for country.
+     */
+    public static final Locale CANADA_FRENCH;
+
+    /**
+     * Useful constant for the root locale.  The root locale is the locale whose
+     * language, country, and variant are empty ("") strings.  This is regarded
+     * as the base locale of all locales, and is used as the language/country
+     * neutral locale for the locale sensitive operations.
+     *
+     * @since 1.6
+     */
+    public static final Locale ROOT;
+
+    private static final Map<BaseLocale, Locale> CONSTANT_LOCALES = new HashMap<>();
+
+    static {
+        ENGLISH = createConstant(BaseLocale.ENGLISH);
+        FRENCH = createConstant(BaseLocale.FRENCH);
+        GERMAN = createConstant(BaseLocale.GERMAN);
+        ITALIAN = createConstant(BaseLocale.ITALIAN);
+        JAPANESE = createConstant(BaseLocale.JAPANESE);
+        KOREAN = createConstant(BaseLocale.KOREAN);
+        CHINESE = createConstant(BaseLocale.CHINESE);
+        SIMPLIFIED_CHINESE = createConstant(BaseLocale.SIMPLIFIED_CHINESE);
+        TRADITIONAL_CHINESE = createConstant(BaseLocale.TRADITIONAL_CHINESE);
+        FRANCE = createConstant(BaseLocale.FRANCE);
+        GERMANY = createConstant(BaseLocale.GERMANY);
+        ITALY = createConstant(BaseLocale.ITALY);
+        JAPAN = createConstant(BaseLocale.JAPAN);
+        KOREA = createConstant(BaseLocale.KOREA);
+        UK = createConstant(BaseLocale.UK);
+        US = createConstant(BaseLocale.US);
+        CANADA = createConstant(BaseLocale.CANADA);
+        CANADA_FRENCH = createConstant(BaseLocale.CANADA_FRENCH);
+        ROOT = createConstant(BaseLocale.ROOT);
+    }
+
+    /** Useful constant for country.
+     */
+    public static final Locale CHINA = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    public static final Locale PRC = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    public static final Locale TAIWAN = TRADITIONAL_CHINESE;
+
+    // Android-added: (internal only): ISO 639-3 generic code for undetermined languages.
+    private static final String UNDETERMINED_LANGUAGE = "und";
+
+    /**
+     * This method must be called only for creating the Locale.*
+     * constants due to making shortcuts.
+     */
+    private static Locale createConstant(byte baseType) {
+        BaseLocale base = BaseLocale.constantBaseLocales[baseType];
+        Locale locale = new Locale(base, null);
+        CONSTANT_LOCALES.put(base, locale);
+        return locale;
+    }
+
+    /**
+     * The key for the private use extension ('x').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    public static final char PRIVATE_USE_EXTENSION = 'x';
+
+    /**
+     * The key for Unicode locale extension ('u').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    public static final char UNICODE_LOCALE_EXTENSION = 'u';
+
+    /** serialization ID
+     */
+    @java.io.Serial
+    static final long serialVersionUID = 9149081749638150636L;
+
+    /**
+     * Enum for specifying the type defined in ISO 3166. This enum is used to
+     * retrieve the two-letter ISO3166-1 alpha-2, three-letter ISO3166-1
+     * alpha-3, four-letter ISO3166-3 country codes.
+     *
+     * @see #getISOCountries(Locale.IsoCountryCode)
+     * @since 9
+     */
+    public static enum IsoCountryCode {
+        /**
+         * PART1_ALPHA2 is used to represent the ISO3166-1 alpha-2 two letter
+         * country codes.
+         */
+        PART1_ALPHA2 {
+            @Override
+            Set<String> createCountryCodeSet() {
+                return Set.of(Locale.getISOCountries());
+            }
+        },
+
+        /**
+         *
+         * PART1_ALPHA3 is used to represent the ISO3166-1 alpha-3 three letter
+         * country codes.
+         */
+        PART1_ALPHA3 {
+            @Override
+            Set<String> createCountryCodeSet() {
+                return LocaleISOData.computeISO3166_1Alpha3Countries();
+            }
+        },
+
+        /**
+         * PART3 is used to represent the ISO3166-3 four letter country codes.
+         */
+        PART3 {
+            @Override
+            Set<String> createCountryCodeSet() {
+                return Set.of(LocaleISOData.ISO3166_3);
+            }
+        };
+
+        /**
+         * Concrete implementation of this method attempts to compute value
+         * for iso3166CodesMap for each IsoCountryCode type key.
+         */
+        abstract Set<String> createCountryCodeSet();
+
+        /**
+         * Map to hold country codes for each ISO3166 part.
+         */
+        private static Map<IsoCountryCode, Set<String>> iso3166CodesMap = new ConcurrentHashMap<>();
+
+        /**
+         * This method is called from Locale class to retrieve country code set
+         * for getISOCountries(type)
+         */
+        static Set<String> retrieveISOCountryCodes(IsoCountryCode type) {
+            return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode::createCountryCodeSet);
+        }
+    }
+
+    /**
+     * Display types for retrieving localized names from the name providers.
+     */
+    private static final int DISPLAY_LANGUAGE  = 0;
+    private static final int DISPLAY_COUNTRY   = 1;
+    private static final int DISPLAY_VARIANT   = 2;
+    private static final int DISPLAY_SCRIPT    = 3;
+    private static final int DISPLAY_UEXT_KEY  = 4;
+    private static final int DISPLAY_UEXT_TYPE = 5;
+
+    /**
+     * Private constructor used by getInstance method
+     */
+    private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
+        this.baseLocale = baseLocale;
+        this.localeExtensions = extensions;
+    }
+
+    /**
+     * Construct a locale from language, country and variant.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * @implNote
+     * <ul>
+     * <li>Obsolete ISO 639 codes ("iw", "ji", and "in") are mapped to
+     * their current forms. See <a href="#legacy_language_codes">Legacy language
+     * codes</a> for more information.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
+     * see <a href="#special_cases_constructor">Special Cases</a> for more information.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the {@code Locale} class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the {@code Locale} class description about valid country values.
+     * @param variant Any arbitrary value used to indicate a variation of a {@code Locale}.
+     * See the {@code Locale} class description for the details.
+     * @throws    NullPointerException thrown if any argument is null.
+     */
+    public Locale(String language, String country, String variant) {
+        if (language == null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
+        localeExtensions = getCompatibilityExtensions(language, "", country, variant);
+    }
+
+    /**
+     * Construct a locale from language and country.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * @implNote
+     * <ul>
+     * <li>Obsolete ISO 639 codes ("iw", "ji", and "in") are mapped to
+     * their current forms. See <a href="#legacy_language_codes">Legacy language
+     * codes</a> for more information.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the {@code Locale} class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the {@code Locale} class description about valid country values.
+     * @throws    NullPointerException thrown if either argument is null.
+     */
+    public Locale(String language, String country) {
+        this(language, country, "");
+    }
+
+    /**
+     * Construct a locale from a language code.
+     * This constructor normalizes the language value to lowercase.
+     * @implNote
+     * <ul>
+     * <li>Obsolete ISO 639 codes ("iw", "ji", and "in") are mapped to
+     * their current forms. See <a href="#legacy_language_codes">Legacy language
+     * codes</a> for more information.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the {@code Locale} class description about
+     * valid language values.
+     * @throws    NullPointerException thrown if argument is null.
+     * @since 1.4
+     */
+    public Locale(String language) {
+        this(language, "", "");
+    }
+
+    /**
+     * Returns a {@code Locale} constructed from the given
+     * {@code language}, {@code country} and
+     * {@code variant}. If the same {@code Locale} instance
+     * is available in the cache, then that instance is
+     * returned. Otherwise, a new {@code Locale} instance is
+     * created and cached.
+     *
+     * @param language lowercase 2 to 8 language code.
+     * @param country uppercase two-letter ISO-3166 code and numeric-3 UN M.49 area code.
+     * @param variant vendor and browser specific code. See class description.
+     * @return the {@code Locale} instance requested
+     * @throws    NullPointerException if any argument is null.
+     */
+    static Locale getInstance(String language, String country, String variant) {
+        return getInstance(language, "", country, variant, null);
+    }
+
+    static Locale getInstance(String language, String script, String country,
+                                      String variant, LocaleExtensions extensions) {
+        if (language== null || script == null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+
+        if (extensions == null) {
+            extensions = getCompatibilityExtensions(language, script, country, variant);
+        }
+
+        BaseLocale baseloc = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
+        return getInstance(baseloc, extensions);
+    }
+
+    static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
+        if (extensions == null) {
+            Locale locale = CONSTANT_LOCALES.get(baseloc);
+            if (locale != null) {
+                return locale;
+            }
+            return Cache.LOCALECACHE.get(baseloc);
+        } else {
+            LocaleKey key = new LocaleKey(baseloc, extensions);
+            return Cache.LOCALECACHE.get(key);
+        }
+    }
+
+    // BEGIN Android-added: Add a static method to clear the stale entries in Zygote
+    /**
+     * This method cleans the stale entries in LOCALECACHE.  This would
+     * be called in Zygote after GC but before fork, and so to avoid the
+     * cleaning of the cache to happen in child processes.
+     *
+     * @hide
+     */
+    public static void cleanCache() {
+        Cache.LOCALECACHE.cleanStaleEntries();
+    }
+    // END Android-added: Add a static method to clear the stale entries in Zygote
+
+    private static class Cache extends LocaleObjectCache<Object, Locale> {
+
+        private static final Cache LOCALECACHE = new Cache();
+
+        private Cache() {
+        }
+
+        @Override
+        protected Locale createObject(Object key) {
+            if (key instanceof BaseLocale) {
+                return new Locale((BaseLocale)key, null);
+            } else {
+                LocaleKey lk = (LocaleKey)key;
+                return new Locale(lk.base, lk.exts);
+            }
+        }
+    }
+
+    private static final class LocaleKey {
+        private final BaseLocale base;
+        private final LocaleExtensions exts;
+        private final int hash;
+
+        private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
+            base = baseLocale;
+            exts = extensions;
+
+            // Calculate the hash value here because it's always used.
+            int h = base.hashCode();
+            if (exts != null) {
+                h ^= exts.hashCode();
+            }
+            hash = h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof LocaleKey other)) {
+                return false;
+            }
+            if (hash != other.hash || !base.equals(other.base)) {
+                return false;
+            }
+            if (exts == null) {
+                return other.exts == null;
+            }
+            return exts.equals(other.exts);
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+    /**
+     * Gets the current value of the default locale for this instance
+     * of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * It can be changed using the
+     * {@link #setDefault(java.util.Locale) setDefault} method.
+     *
+     * @return the default locale for this instance of the Java Virtual Machine
+     */
+    public static Locale getDefault() {
+        // do not synchronize this method - see 4071298
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // return defaultLocale;
+        return NoImagePreloadHolder.defaultLocale;
+    }
+
+    /**
+     * Gets the current value of the default locale for the specified Category
+     * for this instance of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified. It can be changed using the
+     * setDefault(Locale.Category, Locale) method.
+     *
+     * @param category the specified category to get the default locale
+     * @throws NullPointerException if category is null
+     * @return the default locale for the specified Category for this instance
+     *     of the Java Virtual Machine
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public static Locale getDefault(Locale.Category category) {
+        // do not synchronize this method - see 4071298
+        Objects.requireNonNull(category);
+        if (category == Category.DISPLAY) {
+            Locale loc = defaultDisplayLocale; // volatile read
+            if (loc == null) {
+                loc = getDisplayLocale();
+            }
+            return loc;
+        } else {
+            assert category == Category.FORMAT : "Unknown category";
+            Locale loc = defaultFormatLocale; // volatile read
+            if (loc == null) {
+                loc = getFormatLocale();
+            }
+            return loc;
+        }
+    }
+
+    private static synchronized Locale getDisplayLocale() {
+        Locale loc = defaultDisplayLocale;
+        if (loc == null) {
+            loc = defaultDisplayLocale = initDefault(Category.DISPLAY);
+        }
+        return loc;
+    }
+
+
+    private static synchronized Locale getFormatLocale() {
+        Locale loc = defaultFormatLocale;
+        if (loc == null) {
+            loc = defaultFormatLocale = initDefault(Category.FORMAT);
+        }
+        return loc;
+    }
+
+    /**
+     * @hide visible for testing.
+     */
+    // Android-changed: Make initDefault() @hide public for testing.
+    // private static Locale initDefault() {
+    public static Locale initDefault() {
+        // BEGIN Android-added: In initDefault(), prioritize user.locale.
+        // user.locale gets priority
+        final String languageTag = System.getProperty("user.locale", "");
+        if (!languageTag.isEmpty()) {
+            return Locale.forLanguageTag(languageTag);
+        }
+        // END Android-added: In initDefault(), prioritize user.locale.
+
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        // Use System.getProperty(name, default) instead of
+        // AccessController.doPrivileged(new GetPropertyAction(name, default)).
+        // Properties props = GetPropertyAction.privilegedGetProperties();
+        // language = props.getProperty("user.language", "en");
+        // for compatibility, check for old user.region property
+        // region = props.getProperty("user.region");
+        String language, region, script, country, variant;
+        language = System.getProperty("user.language", "en");
+        // for compatibility, check for old user.region property
+        region = System.getProperty("user.region");
+        if (region != null) {
+            // region can be of form country, country_variant, or _variant
+            int i = region.indexOf('_');
+            if (i >= 0) {
+                country = region.substring(0, i);
+                variant = region.substring(i + 1);
+            } else {
+                country = region;
+                variant = "";
+            }
+            script = "";
+        } else {
+            // script = props.getProperty("user.script", "");
+            // country = props.getProperty("user.country", "");
+            // variant = props.getProperty("user.variant", "");
+            script = System.getProperty("user.script", "");
+            country = System.getProperty("user.country", "");
+            variant = System.getProperty("user.variant", "");
+        }
+        // return getInstance(language, script, country, variant,
+        //        getDefaultExtensions(props.getProperty("user.extensions", ""))
+        //            .orElse(null));
+        LocaleExtensions extension = getDefaultExtensions(System.getProperty("user.extensions", ""))
+                .orElse(null);
+        return getInstance(language, script, country, variant, extension);
+        // END Android-changed: Short-circuit legacy security code.
+    }
+
+    private static Locale initDefault(Locale.Category category) {
+        // Android-added: Add NoImagePreloadHolder to allow compile-time initialization.
+        final Locale defaultLocale = NoImagePreloadHolder.defaultLocale;
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        /*
+        Properties props = GetPropertyAction.privilegedGetProperties();
+
+        return getInstance(
+            props.getProperty(category.languageKey,
+                    defaultLocale.getLanguage()),
+            props.getProperty(category.scriptKey,
+                    defaultLocale.getScript()),
+            props.getProperty(category.countryKey,
+                    defaultLocale.getCountry()),
+            props.getProperty(category.variantKey,
+                    defaultLocale.getVariant()),
+            getDefaultExtensions(props.getProperty(category.extensionsKey, ""))
+                .orElse(defaultLocale.getLocaleExtensions()));
+        */
+        return getInstance(
+            System.getProperty(category.languageKey, defaultLocale.getLanguage()),
+            System.getProperty(category.scriptKey, defaultLocale.getScript()),
+            System.getProperty(category.countryKey, defaultLocale.getCountry()),
+            System.getProperty(category.variantKey, defaultLocale.getVariant()),
+            null);
+        // END Android-changed: Short-circuit legacy security code.
+    }
+
+    private static Optional<LocaleExtensions> getDefaultExtensions(String extensionsProp) {
+        if (LocaleUtils.isEmpty(extensionsProp)) {
+            return Optional.empty();
+        }
+
+        LocaleExtensions exts = null;
+        try {
+            exts = new InternalLocaleBuilder()
+                .setExtensions(extensionsProp)
+                .getLocaleExtensions();
+        } catch (LocaleSyntaxException e) {
+            // just ignore this incorrect property
+        }
+
+        return Optional.ofNullable(exts);
+    }
+
+    /**
+     * Sets the default locale for this instance of the Java Virtual Machine.
+     * This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its {@code checkPermission}
+     * method is called with a {@code PropertyPermission("user.language", "write")}
+     * permission before the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas
+     * of functionality, this method should only be used if the caller
+     * is prepared to reinitialize locale-sensitive code running
+     * within the same Java Virtual Machine.
+     * <p>
+     * By setting the default locale with this method, all of the default
+     * locales for each Category are also set to the specified default locale.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow the operation.
+     * @throws NullPointerException if {@code newLocale} is null
+     * @param newLocale the new default locale
+     * @see SecurityManager#checkPermission
+     * @see java.util.PropertyPermission
+     */
+    public static synchronized void setDefault(Locale newLocale) {
+        setDefault(Category.DISPLAY, newLocale);
+        setDefault(Category.FORMAT, newLocale);
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // defaultLocale = newLocale;
+        NoImagePreloadHolder.defaultLocale = newLocale;
+        // Android-added: Keep ICU state in sync with java.util.
+        ICU.setDefaultLocale(newLocale.toLanguageTag());
+    }
+
+    /**
+     * Sets the default locale for the specified Category for this instance
+     * of the Java Virtual Machine. This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its checkPermission method is called
+     * with a PropertyPermission("user.language", "write") permission before
+     * the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas of
+     * functionality, this method should only be used if the caller is
+     * prepared to reinitialize locale-sensitive code running within the
+     * same Java Virtual Machine.
+     *
+     * @param category the specified category to set the default locale
+     * @param newLocale the new default locale
+     * @throws SecurityException if a security manager exists and its
+     *     checkPermission method doesn't allow the operation.
+     * @throws NullPointerException if category and/or newLocale is null
+     * @see SecurityManager#checkPermission(java.security.Permission)
+     * @see PropertyPermission
+     * @see #getDefault(Locale.Category)
+     * @since 1.7
+     */
+    public static synchronized void setDefault(Locale.Category category,
+        Locale newLocale) {
+        if (category == null)
+            throw new NullPointerException("Category cannot be NULL");
+        if (newLocale == null)
+            throw new NullPointerException("Can't set default locale to NULL");
+
+        @SuppressWarnings("removal")
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(new PropertyPermission
+                        ("user.language", "write"));
+        switch (category) {
+        case DISPLAY:
+            defaultDisplayLocale = newLocale;
+            break;
+        case FORMAT:
+            defaultFormatLocale = newLocale;
+            break;
+        default:
+            assert false: "Unknown Category";
+        }
+    }
+
+    // Android-changed: Removed documentation references to LocaleServiceProvider.
+    /**
+     * Returns an array of all installed locales.
+     *
+     * @return An array of installed locales.
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: Use ICU.
+        // return LocaleServiceProviderPool.getAllAvailableLocales();
+        return ICU.getAvailableLocales();
+    }
+
+    /**
+     * Returns a list of all 2-letter country codes defined in ISO 3166.
+     * Can be used to create Locales.
+     * This method is equivalent to {@link #getISOCountries(Locale.IsoCountryCode type)}
+     * with {@code type}  {@link IsoCountryCode#PART1_ALPHA2}.
+     * <p>
+     * <b>Note:</b> The {@code Locale} class also supports other codes for
+     * country (region), such as 3-letter numeric UN M.49 area codes.
+     * Therefore, the list returned by this method does not contain ALL valid
+     * codes that can be used to create Locales.
+     * <p>
+     * Note that this method does not return obsolete 2-letter country codes.
+     * ISO3166-3 codes which designate country codes for those obsolete codes,
+     * can be retrieved from {@link #getISOCountries(Locale.IsoCountryCode type)} with
+     * {@code type}  {@link IsoCountryCode#PART3}.
+     * @return An array of ISO 3166 two-letter country codes.
+     */
+    public static String[] getISOCountries() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoCountries == null) {
+            isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
+        }
+        String[] result = new String[isoCountries.length];
+        System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
+        return result;
+        */
+        return ICU.getISOCountries();
+    }
+
+    /**
+     * Returns a {@code Set} of ISO3166 country codes for the specified type.
+     *
+     * @param type {@link Locale.IsoCountryCode} specified ISO code type.
+     * @see java.util.Locale.IsoCountryCode
+     * @throws NullPointerException if type is null
+     * @return a {@code Set} of ISO country codes for the specified type.
+     * @since 9
+     */
+    public static Set<String> getISOCountries(IsoCountryCode type) {
+        Objects.requireNonNull(type);
+        return IsoCountryCode.retrieveISOCountryCodes(type);
+    }
+
+    // Android-changed: Changed javadoc because Android includes 3-letter codes.
+    /**
+     * Returns a list of all 2-letter language codes and some of 3-letter codes
+     * defined in ISO 639. Can be used to create Locales.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard&mdash; some languages' codes have changed.
+     * The list this function returns includes both the new and the old codes for the
+     * languages whose codes have changed.
+     * <li>The {@code Locale} class also supports language codes up to
+     * 8 characters in length.  Therefore, the list returned by this method does
+     * not contain ALL valid codes that can be used to create Locales.
+     * </ul>
+     *
+     * @return An array of ISO 639 language codes.
+     */
+    public static String[] getISOLanguages() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoLanguages == null) {
+            isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
+        }
+        String[] result = new String[isoLanguages.length];
+        System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
+        return result;
+        */
+        return ICU.getISOLanguages();
+    }
+
+    // Android-removed: Use ICU.
+    // Private helper method getISO2Table(), unused on Android.
+    /*
+    private static String[] getISO2Table(String table) {
+        int len = table.length() / 5;
+        String[] isoTable = new String[len];
+        for (int i = 0, j = 0; i < len; i++, j += 5) {
+            isoTable[i] = table.substring(j, j + 2);
+        }
+        return isoTable;
+    }
+    */
+
+    /**
+     * Returns the language code of this Locale.
+     *
+     * @implNote This method returns the new forms for the obsolete ISO 639
+     * codes ("iw", "ji", and "in"). See <a href="#legacy_language_codes">
+     * Legacy language codes</a> for more information.
+     *
+     * @return The language code, or the empty string if none is defined.
+     * @see #getDisplayLanguage
+     */
+    public String getLanguage() {
+        return baseLocale.getLanguage();
+    }
+
+    /**
+     * Returns the script for this locale, which should
+     * either be the empty string or an ISO 15924 4-letter script
+     * code. The first letter is uppercase and the rest are
+     * lowercase, for example, 'Latn', 'Cyrl'.
+     *
+     * @return The script code, or the empty string if none is defined.
+     * @see #getDisplayScript
+     * @since 1.7
+     */
+    public String getScript() {
+        return baseLocale.getScript();
+    }
+
+    /**
+     * Returns the country/region code for this locale, which should
+     * either be the empty string, an uppercase ISO 3166 2-letter code,
+     * or a UN M.49 3-digit code.
+     *
+     * @return The country/region code, or the empty string if none is defined.
+     * @see #getDisplayCountry
+     */
+    public String getCountry() {
+        return baseLocale.getRegion();
+    }
+
+    /**
+     * Returns the variant code for this locale.
+     *
+     * @return The variant code, or the empty string if none is defined.
+     * @see #getDisplayVariant
+     */
+    public String getVariant() {
+        return baseLocale.getVariant();
+    }
+
+    /**
+     * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
+     * extensions</a>.
+     *
+     * @return {@code true} if this {@code Locale} has any extensions
+     * @since 1.8
+     */
+    public boolean hasExtensions() {
+        return localeExtensions != null;
+    }
+
+    /**
+     * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
+     * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
+     * is returned.
+     *
+     * @return a copy of this {@code Locale} with no extensions, or {@code this}
+     *         if {@code this} has no extensions
+     * @since 1.8
+     */
+    public Locale stripExtensions() {
+        return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
+    }
+
+    /**
+     * Returns the extension (or private use) value associated with
+     * the specified key, or null if there is no extension
+     * associated with the key. To be well-formed, the key must be one
+     * of {@code [0-9A-Za-z]}. Keys are case-insensitive, so
+     * for example 'z' and 'Z' represent the same extension.
+     *
+     * @param key the extension key
+     * @return The extension, or null if this locale defines no
+     * extension for the specified key.
+     * @throws IllegalArgumentException if key is not well-formed
+     * @see #PRIVATE_USE_EXTENSION
+     * @see #UNICODE_LOCALE_EXTENSION
+     * @since 1.7
+     */
+    public String getExtension(char key) {
+        if (!LocaleExtensions.isValidKey(key)) {
+            throw new IllegalArgumentException("Ill-formed extension key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
+    }
+
+    /**
+     * Returns the set of extension keys associated with this locale, or the
+     * empty set if it has no extensions. The returned set is unmodifiable.
+     * The keys will all be lower-case.
+     *
+     * @return The set of extension keys, or the empty set if this locale has
+     * no extensions.
+     * @since 1.7
+     */
+    public Set<Character> getExtensionKeys() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getKeys();
+    }
+
+    /**
+     * Returns the set of unicode locale attributes associated with
+     * this locale, or the empty set if it has no attributes. The
+     * returned set is unmodifiable.
+     *
+     * @return The set of attributes.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleAttributes() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleAttributes();
+    }
+
+    /**
+     * Returns the Unicode locale type associated with the specified Unicode locale key
+     * for this locale. Returns the empty string for keys that are defined with no type.
+     * Returns null if the key is not defined. Keys are case-insensitive. The key must
+     * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
+     * thrown.
+     *
+     * @param key the Unicode locale key
+     * @return The Unicode locale type associated with the key, or null if the
+     * locale does not define the key.
+     * @throws IllegalArgumentException if the key is not well-formed
+     * @throws NullPointerException if {@code key} is null
+     * @since 1.7
+     */
+    public String getUnicodeLocaleType(String key) {
+        if (!isUnicodeExtensionKey(key)) {
+            throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
+    }
+
+    /**
+     * Returns the set of Unicode locale keys defined by this locale, or the empty set if
+     * this locale has none.  The returned set is immutable.  Keys are all lower case.
+     *
+     * @return The set of Unicode locale keys, or the empty set if this locale has
+     * no Unicode locale keywords.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleKeys() {
+        if (localeExtensions == null) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleKeys();
+    }
+
+    /**
+     * Package locale method returning the Locale's BaseLocale,
+     * used by ResourceBundle
+     * @return base locale of this Locale
+     */
+    BaseLocale getBaseLocale() {
+        return baseLocale;
+    }
+
+    /**
+     * Package private method returning the Locale's LocaleExtensions,
+     * used by ResourceBundle.
+     * @return locale extensions of this Locale,
+     *         or {@code null} if no extensions are defined
+     */
+     LocaleExtensions getLocaleExtensions() {
+         return localeExtensions;
+     }
+
+    /**
+     * Returns a string representation of this {@code Locale}
+     * object, consisting of language, country, variant, script,
+     * and extensions as below:
+     * <blockquote>
+     * language + "_" + country + "_" + (variant + "_#" | "#") + script + "_" + extensions
+     * </blockquote>
+     *
+     * Language is always lower case, country is always upper case, script is always title
+     * case, and extensions are always lower case.  Extensions and private use subtags
+     * will be in canonical order as explained in {@link #toLanguageTag}.
+     *
+     * <p>When the locale has neither script nor extensions, the result is the same as in
+     * Java 6 and prior.
+     *
+     * <p>If both the language and country fields are missing, this function will return
+     * the empty string, even if the variant, script, or extensions field is present (you
+     * can't have a locale with just a variant, the variant must accompany a well-formed
+     * language or country code).
+     *
+     * <p>If script or extensions are present and variant is missing, no underscore is
+     * added before the "#".
+     *
+     * <p>This behavior is designed to support debugging and to be compatible with
+     * previous uses of {@code toString} that expected language, country, and variant
+     * fields only.  To represent a Locale as a String for interchange purposes, use
+     * {@link #toLanguageTag}.
+     *
+     * <p>Examples: <ul>
+     * <li>{@code en}</li>
+     * <li>{@code de_DE}</li>
+     * <li>{@code _GB}</li>
+     * <li>{@code en_US_WIN}</li>
+     * <li>{@code de__POSIX}</li>
+     * <li>{@code zh_CN_#Hans}</li>
+     * <li>{@code zh_TW_#Hant_x-java}</li>
+     * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
+     *
+     * @return A string representation of the Locale, for debugging.
+     * @see #getDisplayName
+     * @see #toLanguageTag
+     */
+    @Override
+    public final String toString() {
+        boolean l = !baseLocale.getLanguage().isEmpty();
+        boolean s = !baseLocale.getScript().isEmpty();
+        boolean r = !baseLocale.getRegion().isEmpty();
+        boolean v = !baseLocale.getVariant().isEmpty();
+        boolean e = localeExtensions != null && !localeExtensions.getID().isEmpty();
+
+        StringBuilder result = new StringBuilder(baseLocale.getLanguage());
+        if (r || (l && (v || s || e))) {
+            result.append('_')
+                .append(baseLocale.getRegion()); // This may just append '_'
+        }
+        if (v && (l || r)) {
+            result.append('_')
+                .append(baseLocale.getVariant());
+        }
+
+        if (s && (l || r)) {
+            result.append("_#")
+                .append(baseLocale.getScript());
+        }
+
+        if (e && (l || r)) {
+            result.append('_');
+            if (!s) {
+                result.append('#');
+            }
+            result.append(localeExtensions.getID());
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Returns a well-formed IETF BCP 47 language tag representing
+     * this locale.
+     *
+     * <p>If this {@code Locale} has a language, country, or
+     * variant that does not satisfy the IETF BCP 47 language tag
+     * syntax requirements, this method handles these fields as
+     * described below:
+     *
+     * <p><b>Language:</b> If language is empty, or not <a
+     * href="#def_language" >well-formed</a> (for example "a" or
+     * "e2"), it will be emitted as "und" (Undetermined).
+     *
+     * <p><b>Country:</b> If country is not <a
+     * href="#def_region">well-formed</a> (for example "12" or "USA"),
+     * it will be omitted.
+     *
+     * <p><b>Variant:</b> If variant <b>is</b> <a
+     * href="#def_variant">well-formed</a>, each sub-segment
+     * (delimited by '-' or '_') is emitted as a subtag.  Otherwise:
+     * <ul>
+     *
+     * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
+     * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
+     * ill-formed sub-segment and all following will be appended to
+     * the private use subtag.  The first appended subtag will be
+     * "lvariant", followed by the sub-segments in order, separated by
+     * hyphen. For example, "x-lvariant-WIN",
+     * "Oracle-x-lvariant-JDK-Standard-Edition".
+     *
+     * <li>if any sub-segment does not match
+     * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
+     * and the problematic sub-segment and all following sub-segments
+     * will be omitted.  If the remainder is non-empty, it will be
+     * emitted as a private use subtag as above (even if the remainder
+     * turns out to be well-formed).  For example,
+     * "Solaris_isjustthecoolestthing" is emitted as
+     * "x-lvariant-Solaris", not as "solaris".</li></ul>
+     *
+     * <p><b>Special Conversions:</b> Java supports some old locale
+     * representations, including deprecated ISO language codes,
+     * for compatibility. This method performs the following
+     * conversions:
+     * <ul>
+     *
+     * <li>Deprecated ISO language codes "iw", "ji", and "in" are
+     * converted to "he", "yi", and "id", respectively.
+     *
+     * <li>A locale with language "no", country "NO", and variant
+     * "NY", representing Norwegian Nynorsk (Norway), is converted
+     * to a language tag "nn-NO".</li></ul>
+     *
+     * <p><b>Note:</b> Although the language tag created by this
+     * method is well-formed (satisfies the syntax requirements
+     * defined by the IETF BCP 47 specification), it is not
+     * necessarily a valid BCP 47 language tag.  For example,
+     * <pre>
+     *   new Locale("xx", "YY").toLanguageTag();</pre>
+     *
+     * will return "xx-YY", but the language subtag "xx" and the
+     * region subtag "YY" are invalid because they are not registered
+     * in the IANA Language Subtag Registry.
+     *
+     * @return a BCP47 language tag representing the locale
+     * @see #forLanguageTag(String)
+     * @since 1.7
+     */
+    public String toLanguageTag() {
+        if (languageTag != null) {
+            return languageTag;
+        }
+
+        LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
+        StringBuilder buf = new StringBuilder();
+
+        String subtag = tag.getLanguage();
+        if (!subtag.isEmpty()) {
+            buf.append(LanguageTag.canonicalizeLanguage(subtag));
+        }
+
+        subtag = tag.getScript();
+        if (!subtag.isEmpty()) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeScript(subtag));
+        }
+
+        subtag = tag.getRegion();
+        if (!subtag.isEmpty()) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeRegion(subtag));
+        }
+
+        List<String>subtags = tag.getVariants();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(s);
+        }
+
+        subtags = tag.getExtensions();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeExtension(s));
+        }
+
+        subtag = tag.getPrivateuse();
+        if (!subtag.isEmpty()) {
+            if (buf.length() > 0) {
+                buf.append(LanguageTag.SEP);
+            }
+            buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(subtag);
+        }
+
+        String langTag = buf.toString();
+        synchronized (this) {
+            if (languageTag == null) {
+                languageTag = langTag;
+            }
+        }
+        return languageTag;
+    }
+
+    /**
+     * Returns a locale for the specified IETF BCP 47 language tag string.
+     *
+     * <p>If the specified language tag contains any ill-formed subtags,
+     * the first such subtag and all following subtags are ignored.  Compare
+     * to {@link Locale.Builder#setLanguageTag} which throws an exception
+     * in this case.
+     *
+     * <p>The following <b>conversions</b> are performed:<ul>
+     *
+     * <li>The language code "und" is mapped to language "".
+     *
+     * <li>The language codes "iw", "ji", and "in" are mapped to "he",
+     * "yi", and "id" respectively. (This is the same canonicalization
+     * that's done in Locale's constructors.) See
+     * <a href="#legacy_language_codes">Legacy language codes</a>
+     * for more information.
+     *
+     * <li>The portion of a private use subtag prefixed by "lvariant",
+     * if any, is removed and appended to the variant field in the
+     * result locale (without case normalization).  If it is then
+     * empty, the private use subtag is discarded:
+     *
+     * <pre>
+     *     Locale loc;
+     *     loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
+     *     loc.getVariant(); // returns "POSIX"
+     *     loc.getExtension('x'); // returns null
+     *
+     *     loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
+     *     loc.getVariant(); // returns "POSIX_Abc_Def"
+     *     loc.getExtension('x'); // returns "urp"
+     * </pre>
+     *
+     * <li>When the languageTag argument contains an extlang subtag,
+     * the first such subtag is used as the language, and the primary
+     * language subtag and other extlang subtags are ignored:
+     *
+     * <pre>
+     *     Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
+     *     Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
+     * </pre>
+     *
+     * <li>Case is normalized except for variant tags, which are left
+     * unchanged.  Language is normalized to lower case, script to
+     * title case, country to upper case, and extensions to lower
+     * case.
+     *
+     * <li>If, after processing, the locale would exactly match either
+     * ja_JP_JP or th_TH_TH with no extensions, the appropriate
+     * extensions are added as though the constructor had been called:
+     *
+     * <pre>
+     *    Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
+     *    // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
+     *    Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
+     *    // returns "th-TH-u-nu-thai-x-lvariant-TH"
+     * </pre></ul>
+     *
+     * <p>This implements the 'Language-Tag' production of BCP47, and
+     * so supports legacy (regular and irregular, referred to as
+     * "Type: grandfathered" in BCP47) as well as
+     * private use language tags.  Stand alone private use tags are
+     * represented as empty language and extension 'x-whatever',
+     * and legacy tags are converted to their canonical replacements
+     * where they exist.
+     *
+     * <p>Legacy tags with canonical replacements are as follows:
+     *
+     * <table class="striped">
+     * <caption style="display:none">Legacy tags with canonical replacements</caption>
+     * <thead style="text-align:center">
+     * <tr><th scope="col" style="padding: 0 2px">legacy tag</th><th scope="col" style="padding: 0 2px">modern replacement</th></tr>
+     * </thead>
+     * <tbody style="text-align:center">
+     * <tr><th scope="row">art-lojban</th><td>jbo</td></tr>
+     * <tr><th scope="row">i-ami</th><td>ami</td></tr>
+     * <tr><th scope="row">i-bnn</th><td>bnn</td></tr>
+     * <tr><th scope="row">i-hak</th><td>hak</td></tr>
+     * <tr><th scope="row">i-klingon</th><td>tlh</td></tr>
+     * <tr><th scope="row">i-lux</th><td>lb</td></tr>
+     * <tr><th scope="row">i-navajo</th><td>nv</td></tr>
+     * <tr><th scope="row">i-pwn</th><td>pwn</td></tr>
+     * <tr><th scope="row">i-tao</th><td>tao</td></tr>
+     * <tr><th scope="row">i-tay</th><td>tay</td></tr>
+     * <tr><th scope="row">i-tsu</th><td>tsu</td></tr>
+     * <tr><th scope="row">no-bok</th><td>nb</td></tr>
+     * <tr><th scope="row">no-nyn</th><td>nn</td></tr>
+     * <tr><th scope="row">sgn-BE-FR</th><td>sfb</td></tr>
+     * <tr><th scope="row">sgn-BE-NL</th><td>vgt</td></tr>
+     * <tr><th scope="row">sgn-CH-DE</th><td>sgg</td></tr>
+     * <tr><th scope="row">zh-guoyu</th><td>cmn</td></tr>
+     * <tr><th scope="row">zh-hakka</th><td>hak</td></tr>
+     * <tr><th scope="row">zh-min-nan</th><td>nan</td></tr>
+     * <tr><th scope="row">zh-xiang</th><td>hsn</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>Legacy tags with no modern replacement will be
+     * converted as follows:
+     *
+     * <table class="striped">
+     * <caption style="display:none">Legacy tags with no modern replacement</caption>
+     * <thead style="text-align:center">
+     * <tr><th scope="col" style="padding: 0 2px">legacy tag</th><th scope="col" style="padding: 0 2px">converts to</th></tr>
+     * </thead>
+     * <tbody style="text-align:center">
+     * <tr><th scope="row">cel-gaulish</th><td>xtg-x-cel-gaulish</td></tr>
+     * <tr><th scope="row">en-GB-oed</th><td>en-GB-x-oed</td></tr>
+     * <tr><th scope="row">i-default</th><td>en-x-i-default</td></tr>
+     * <tr><th scope="row">i-enochian</th><td>und-x-i-enochian</td></tr>
+     * <tr><th scope="row">i-mingo</th><td>see-x-i-mingo</td></tr>
+     * <tr><th scope="row">zh-min</th><td>nan-x-zh-min</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>For a list of all legacy tags, see the
+     * IANA Language Subtag Registry (search for "Type: grandfathered").
+     *
+     * <p><b>Note</b>: there is no guarantee that {@code toLanguageTag}
+     * and {@code forLanguageTag} will round-trip.
+     *
+     * @param languageTag the language tag
+     * @return The locale that best represents the language tag.
+     * @throws NullPointerException if {@code languageTag} is {@code null}
+     * @see #toLanguageTag()
+     * @see java.util.Locale.Builder#setLanguageTag(String)
+     * @since 1.7
+     */
+    public static Locale forLanguageTag(String languageTag) {
+        LanguageTag tag = LanguageTag.parse(languageTag, null);
+        InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+        bldr.setLanguageTag(tag);
+        BaseLocale base = bldr.getBaseLocale();
+        LocaleExtensions exts = bldr.getLocaleExtensions();
+        if (exts == null && !base.getVariant().isEmpty()) {
+            exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
+                                              base.getRegion(), base.getVariant());
+        }
+        return getInstance(base, exts);
+    }
+
+    /**
+     * Returns a three-letter abbreviation of this locale's language.
+     * If the language matches an ISO 639-1 two-letter code, the
+     * corresponding ISO 639-2/T three-letter lowercase code is
+     * returned.  The ISO 639-2 language codes can be found on-line,
+     * see "Codes for the Representation of Names of Languages Part 2:
+     * Alpha-3 Code".  If the locale specifies a three-letter
+     * language, the language is returned as is.  If the locale does
+     * not specify a language the empty string is returned.
+     *
+     * @return A three-letter abbreviation of this locale's language.
+     * @throws    MissingResourceException Throws MissingResourceException if
+     * three-letter language abbreviation is not available for this locale.
+     */
+    public String getISO3Language() throws MissingResourceException {
+        String lang = baseLocale.getLanguage();
+        if (lang.length() == 3) {
+            return lang;
+        }
+        // BEGIN Android-added: app compat: Use "" as ISO3 for empty languages.
+        else if (lang.isEmpty()) {
+            return "";
+        }
+        // END Android-added: app compat: Use "" as ISO3 for empty languages.
+
+        // BEGIN Android-changed: Use ICU.
+        // String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
+        // if (language3 == null) {
+        String language3 = ICU.getISO3Language(lang);
+        if (!lang.isEmpty() && language3.isEmpty()) {
+        // END Android-changed: Use ICU.
+            throw new MissingResourceException("Couldn't find 3-letter language code for "
+                    + lang, "FormatData_" + toString(), "ShortLanguage");
+        }
+        return language3;
+    }
+
+    /**
+     * Returns a three-letter abbreviation for this locale's country.
+     * If the country matches an ISO 3166-1 alpha-2 code, the
+     * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
+     * If the locale doesn't specify a country, this will be the empty
+     * string.
+     *
+     * <p>The ISO 3166-1 codes can be found on-line.
+     *
+     * @return A three-letter abbreviation of this locale's country.
+     * @throws    MissingResourceException Throws MissingResourceException if the
+     * three-letter country abbreviation is not available for this locale.
+     */
+    public String getISO3Country() throws MissingResourceException {
+        // BEGIN Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+        // String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
+        // if (country3 == null) {
+        final String region = baseLocale.getRegion();
+        // Note that this will return an UN.M49 region code
+        if (region.length() == 3) {
+            return baseLocale.getRegion();
+        } else if (region.isEmpty()) {
+            return "";
+        }
+
+        // Prefix "en-" because ICU doesn't really care about what the language is.
+        String country3 = ICU.getISO3Country("en-" + region);
+        if (!region.isEmpty() && country3.isEmpty()) {
+        // END Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+            throw new MissingResourceException("Couldn't find 3-letter country code for "
+                    + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
+        }
+        return country3;
+    }
+
+    // Android-removed: Use ICU.
+    // getISO3Code() is unused on Android.
+    /*
+    private static String getISO3Code(String iso2Code, String table) {
+        int codeLength = iso2Code.length();
+        if (codeLength == 0) {
+            return "";
+        }
+
+        int tableLength = table.length();
+        int index = tableLength;
+        if (codeLength == 2) {
+            char c1 = iso2Code.charAt(0);
+            char c2 = iso2Code.charAt(1);
+            for (index = 0; index < tableLength; index += 5) {
+                if (table.charAt(index) == c1
+                    && table.charAt(index + 1) == c2) {
+                    break;
+                }
+            }
+        }
+        return index < tableLength ? table.substring(index + 2, index + 5) : null;
+    }
+    */
+
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a language, this function returns the empty string.
+     *
+     * @return The name of the display language.
+     */
+    public final String getDisplayLanguage() {
+        return getDisplayLanguage(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; backwards compatibility hacks; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized according to inLocale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a language,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display language.
+     * @return The name of the display language appropriate to the given locale.
+     * @throws    NullPointerException if {@code inLocale} is {@code null}
+     *
+    public String getDisplayLanguage(Locale inLocale) {
+        return getDisplayString(baseLocale.getLanguage(), null, inLocale, DISPLAY_LANGUAGE);
+    }
+    */
+    /**
+     * Returns the name of this locale's language, localized to {@code locale}.
+     * If the language name is unknown, the language code is returned.
+     */
+    public String getDisplayLanguage(Locale locale) {
+        String languageCode = baseLocale.getLanguage();
+        if (languageCode.isEmpty()) {
+            return "";
+        }
+
+        // Hacks for backward compatibility.
+        //
+        // Our language tag will contain "und" if the languageCode is invalid
+        // or missing. ICU will then return "langue indéterminée" or the equivalent
+        // display language for the indeterminate language code.
+        //
+        // Sigh... ugh... and what not.
+        final String normalizedLanguage = normalizeAndValidateLanguage(
+                languageCode, false /* strict */);
+        if (UNDETERMINED_LANGUAGE.equals(normalizedLanguage)) {
+            return languageCode;
+        }
+
+        // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
+        // cover the frameworks' tracks when they were using "tl" instead of "fil".
+        String result = LocaleNative.getDisplayLanguage(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayLanguage(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateLanguage(String language, boolean strict) {
+        if (language == null || language.isEmpty()) {
+            return "";
+        }
+
+        final String lowercaseLanguage = language.toLowerCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(lowercaseLanguage, 2, 3)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid language: " + language);
+            } else {
+                return UNDETERMINED_LANGUAGE;
+            }
+        }
+
+        return lowercaseLanguage;
+    }
+
+    /*
+     * Checks whether a given string is an ASCII alphanumeric string.
+     */
+    private static boolean isAsciiAlphaNum(String string) {
+        for (int i = 0; i < string.length(); i++) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z' ||
+                    character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale's script that is appropriate for display to
+     * the user. If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  Returns
+     * the empty string if this locale doesn't specify a script code.
+     *
+     * @return the display name of the script code for the current default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayScript() {
+        return getDisplayScript(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's script that is appropriate
+     * for display to the user. If possible, the name will be
+     * localized for the given locale. Returns the empty string if
+     * this locale doesn't specify a script code.
+     *
+     * @param inLocale The locale for which to retrieve the display script.
+     * @return the display name of the script code for the current default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @throws NullPointerException if {@code inLocale} is {@code null}
+     * @since 1.7
+     */
+    public String getDisplayScript(Locale inLocale) {
+        // BEGIN Android-changed: Use ICU.
+        // return getDisplayString(baseLocale.getScript(), null, inLocale, DISPLAY_SCRIPT);
+        String scriptCode = baseLocale.getScript();
+        if (scriptCode.isEmpty()) {
+            return "";
+        }
+
+        String result = LocaleNative.getDisplayScript(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayScript(this, Locale.getDefault(Category.DISPLAY));
+        }
+
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a country, this function returns the empty string.
+     *
+     * @return The name of the country appropriate to the locale.
+     */
+    public final String getDisplayCountry() {
+        return getDisplayCountry(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized according to inLocale.
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a country,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display country.
+     * @return The name of the country appropriate to the given locale.
+     * @throws    NullPointerException if {@code inLocale} is {@code null}
+     *
+    public String getDisplayCountry(Locale inLocale) {
+        return getDisplayString(baseLocale.getRegion(), null, inLocale, DISPLAY_COUNTRY);
+    }
+
+    private String getDisplayString(String code, String cat, Locale inLocale, int type) {
+        Objects.requireNonNull(inLocale);
+        Objects.requireNonNull(code);
+
+        if (code.isEmpty()) {
+            return "";
+        }
+
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
+        String rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code);
+        String result = pool.getLocalizedObject(
+                                LocaleNameGetter.INSTANCE,
+                                inLocale, rbKey, type, code, cat);
+        return result != null ? result : code;
+    }
+    */
+    /**
+     * Returns the name of this locale's country, localized to {@code locale}.
+     * Returns the empty string if this locale does not correspond to a specific
+     * country.
+     */
+    public String getDisplayCountry(Locale locale) {
+        String countryCode = baseLocale.getRegion();
+        if (countryCode.isEmpty()) {
+            return "";
+        }
+
+        final String normalizedRegion = normalizeAndValidateRegion(
+                countryCode, false /* strict */);
+        if (normalizedRegion.isEmpty()) {
+            return countryCode;
+        }
+
+        String result = LocaleNative.getDisplayCountry(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayCountry(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateRegion(String region, boolean strict) {
+        if (region == null || region.isEmpty()) {
+            return "";
+        }
+
+        final String uppercaseRegion = region.toUpperCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(uppercaseRegion, 2, 2) &&
+                !isUnM49AreaCode(uppercaseRegion)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid region: " + region);
+            } else {
+                return "";
+            }
+        }
+
+        return uppercaseRegion;
+    }
+
+    private static boolean isValidBcp47Alpha(String string, int lowerBound, int upperBound) {
+        final int length = string.length();
+        if (length < lowerBound || length > upperBound) {
+            return false;
+        }
+
+        for (int i = 0; i < length; ++i) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * A UN M.49 is a 3 digit numeric code.
+     */
+    private static boolean isUnM49AreaCode(String code) {
+        if (code.length() != 3) {
+            return false;
+        }
+
+        for (int i = 0; i < 3; ++i) {
+            final char character = code.charAt(i);
+            if (!(character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @return The name of the display variant code appropriate to the locale.
+     */
+    public final String getDisplayVariant() {
+        return getDisplayVariant(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for inLocale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display variant code.
+     * @return The name of the display variant code appropriate to the given locale.
+     * @throws    NullPointerException if {@code inLocale} is {@code null}
+     */
+    public String getDisplayVariant(Locale inLocale) {
+// BEGIN Android-changed: Documentation and behavior of getDisplay*().
+// Use ICU; added private helper methods.
+/*
+        if (baseLocale.getVariant().isEmpty())
+            return "";
+
+        LocaleResources lr = LocaleProviderAdapter
+            .getResourceBundleBased()
+            .getLocaleResources(inLocale);
+
+        String names[] = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a list, and use
+        // them to format the list.
+        return formatList(names,
+                          lr.getLocaleName("ListCompositionPattern"));
+    }
+*/
+        String variantCode = baseLocale.getVariant();
+        if (variantCode.isEmpty()) {
+            return "";
+        }
+
+        try {
+            normalizeAndValidateVariant(variantCode);
+        } catch (IllformedLocaleException ilfe) {
+            return variantCode;
+        }
+
+        String result = LocaleNative.getDisplayVariant(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayVariant(this, Locale.getDefault());
+        }
+
+        // The "old style" locale constructors allow us to pass in variants that aren't
+        // valid BCP-47 variant subtags. When that happens, toLanguageTag will not emit
+        // them. Note that we know variantCode.length() > 0 due to the isEmpty check at
+        // the beginning of this function.
+        if (result.isEmpty()) {
+            return variantCode;
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateVariant(String variant) {
+        if (variant == null || variant.isEmpty()) {
+            return "";
+        }
+
+        // Note that unlike extensions, we canonicalize to lower case alphabets
+        // and underscores instead of hyphens.
+        final String normalizedVariant = variant.replace('-', '_');
+        String[] subTags = normalizedVariant.split("_");
+
+        for (String subTag : subTags) {
+            if (!isValidVariantSubtag(subTag)) {
+                throw new IllformedLocaleException("Invalid variant: " + variant);
+            }
+        }
+
+        return normalizedVariant;
+    }
+
+    private static boolean isValidVariantSubtag(String subTag) {
+        // The BCP-47 spec states that :
+        // - Subtags can be between [5, 8] alphanumeric chars in length.
+        // - Subtags that start with a number are allowed to be 4 chars in length.
+        if (subTag.length() >= 5 && subTag.length() <= 8) {
+            if (isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        } else if (subTag.length() == 4) {
+            final char firstChar = subTag.charAt(0);
+            if ((firstChar >= '0' && firstChar <= '9') && isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+// END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale that is appropriate for display to the
+     * user. This will be the values returned by getDisplayLanguage(),
+     * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
+     * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
+     * assembled into a single string. The non-empty values are used in order, with
+     * the second and subsequent names in parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant(, extension)*)<br>
+     * language (country(, extension)*)<br>
+     * language (variant(, extension)*)<br>
+     * script (country(, extension)*)<br>
+     * country (extension)*<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale. The field
+     * separator in the above parentheses, denoted as a comma character, may
+     * be localized depending on the locale. If the language, script, country,
+     * and variant fields are all empty, this function returns the empty string.
+     *
+     * @return The name of the locale appropriate to display.
+     */
+    public final String getDisplayName() {
+        return getDisplayName(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    /*
+    /**
+     * Returns a name for the locale that is appropriate for display
+     * to the user.  This will be the values returned by
+     * getDisplayLanguage(), getDisplayScript(),getDisplayCountry()
+     * getDisplayVariant(), and optional <a href="./Locale.html#def_locale_extension">
+     * Unicode extensions</a> assembled into a single string. The non-empty
+     * values are used in order, with the second and subsequent names in
+     * parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant(, extension)*)<br>
+     * language (country(, extension)*)<br>
+     * language (variant(, extension)*)<br>
+     * script (country(, extension)*)<br>
+     * country (extension)*<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale. The field
+     * separator in the above parentheses, denoted as a comma character, may
+     * be localized depending on the locale. If the language, script, country,
+     * and variant fields are all empty, this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display name.
+     * @return The name of the locale appropriate to display.
+     * @throws NullPointerException if {@code inLocale} is {@code null}
+     *
+    public String getDisplayName(Locale inLocale) {
+        LocaleResources lr =  LocaleProviderAdapter
+            .getResourceBundleBased()
+            .getLocaleResources(inLocale);
+
+        String languageName = getDisplayLanguage(inLocale);
+        String scriptName = getDisplayScript(inLocale);
+        String countryName = getDisplayCountry(inLocale);
+        String[] variantNames = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a display name.
+        String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
+        String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
+
+        // The display name consists of a main name, followed by qualifiers.
+        // Typically, the format is "MainName (Qualifier, Qualifier)" but this
+        // depends on what pattern is stored in the display locale.
+        String   mainName;
+        String[] qualifierNames;
+
+        // The main name is the language, or if there is no language, the script,
+        // then if no script, the country. If there is no language/script/country
+        // (an anomalous situation) then the display name is simply the variant's
+        // display name.
+        if (languageName.isEmpty() && scriptName.isEmpty() && countryName.isEmpty()) {
+            if (variantNames.length == 0) {
+                return "";
+            } else {
+                return formatList(variantNames, listCompositionPattern);
+            }
+        }
+        ArrayList<String> names = new ArrayList<>(4);
+        if (!languageName.isEmpty()) {
+            names.add(languageName);
+        }
+        if (!scriptName.isEmpty()) {
+            names.add(scriptName);
+        }
+        if (!countryName.isEmpty()) {
+            names.add(countryName);
+        }
+        if (variantNames.length != 0) {
+            names.addAll(Arrays.asList(variantNames));
+        }
+
+        // add Unicode extensions
+        if (localeExtensions != null) {
+            localeExtensions.getUnicodeLocaleAttributes().stream()
+                .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
+                .forEach(names::add);
+            localeExtensions.getUnicodeLocaleKeys().stream()
+                .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
+                .forEach(names::add);
+        }
+
+        // The first one in the main name
+        mainName = names.get(0);
+
+        // Others are qualifiers
+        int numNames = names.size();
+        qualifierNames = (numNames > 1) ?
+                names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
+
+        // Create an array whose first element is the number of remaining
+        // elements.  This serves as a selector into a ChoiceFormat pattern from
+        // the resource.  The second and third elements are the main name and
+        // the qualifier; if there are no qualifiers, the third element is
+        // unused by the format pattern.
+        Object[] displayNames = {
+            qualifierNames.length != 0 ? 2 : 1,
+            mainName,
+            // We could also just call formatList() and have it handle the empty
+            // list case, but this is more efficient, and we want it to be
+            // efficient since all the language-only locales will not have any
+            // qualifiers.
+            qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null
+        };
+
+        if (displayNamePattern != null) {
+            return new MessageFormat(displayNamePattern).format(displayNames);
+        }
+        else {
+            // If we cannot get the message format pattern, then we use a simple
+            // hard-coded pattern.  This should not occur in practice unless the
+            // installation is missing some core files (FormatData etc.).
+            StringBuilder result = new StringBuilder();
+            result.append((String)displayNames[1]);
+            if (displayNames.length > 2) {
+                result.append(" (");
+                result.append((String)displayNames[2]);
+                result.append(')');
+            }
+            return result.toString();
+        }
+    }
+    */
+    /**
+     * Returns this locale's language name, country name, and variant, localized
+     * to {@code locale}. The exact output form depends on whether this locale
+     * corresponds to a specific language, script, country and variant.
+     *
+     * <p>For example:
+     * <ul>
+     * <li>{@code new Locale("en").getDisplayName(Locale.US)} -> {@code English}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.US)} -> {@code English (United States)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.US)} -> {@code English (United States,Computer)}
+     * <li>{@code Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US)} -> {@code Chinese (Traditional Han,China)}
+     * <li>{@code new Locale("en").getDisplayName(Locale.FRANCE)} -> {@code anglais}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis,informatique)}.
+     * </ul>
+     */
+    public String getDisplayName(Locale locale) {
+        int count = 0;
+        StringBuilder buffer = new StringBuilder();
+        String languageCode = baseLocale.getLanguage();
+        if (!languageCode.isEmpty()) {
+            String displayLanguage = getDisplayLanguage(locale);
+            buffer.append(displayLanguage.isEmpty() ? languageCode : displayLanguage);
+            ++count;
+        }
+        String scriptCode = baseLocale.getScript();
+        if (!scriptCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            }
+            String displayScript = getDisplayScript(locale);
+            buffer.append(displayScript.isEmpty() ? scriptCode : displayScript);
+            ++count;
+        }
+        String countryCode = baseLocale.getRegion();
+        if (!countryCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2) {
+                buffer.append(",");
+            }
+            String displayCountry = getDisplayCountry(locale);
+            buffer.append(displayCountry.isEmpty() ? countryCode : displayCountry);
+            ++count;
+        }
+        String variantCode = baseLocale.getVariant();
+        if (!variantCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2 || count == 3) {
+                buffer.append(",");
+            }
+            String displayVariant = getDisplayVariant(locale);
+            buffer.append(displayVariant.isEmpty() ? variantCode : displayVariant);
+            ++count;
+        }
+        if (count > 1) {
+            buffer.append(")");
+        }
+        return buffer.toString();
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Overrides Cloneable.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Locale that = (Locale)super.clone();
+            return that;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Override hashCode.
+     * Since Locales are often used in hashtables, caches the value
+     * for speed.
+     */
+    @Override
+    public int hashCode() {
+        int hc = hashCodeValue;
+        if (hc == 0) {
+            hc = baseLocale.hashCode();
+            if (localeExtensions != null) {
+                hc ^= localeExtensions.hashCode();
+            }
+            hashCodeValue = hc;
+        }
+        return hc;
+    }
+
+    // Overrides
+
+    /**
+     * Returns true if this Locale is equal to another object.  A Locale is
+     * deemed equal to another Locale with identical language, script, country,
+     * variant and extensions, and unequal to all other objects.
+     *
+     * @return true if this Locale is equal to the specified object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)                      // quick check
+            return true;
+        if (!(obj instanceof Locale))
+            return false;
+        BaseLocale otherBase = ((Locale)obj).baseLocale;
+        if (!baseLocale.equals(otherBase)) {
+            return false;
+        }
+        if (localeExtensions == null) {
+            return ((Locale)obj).localeExtensions == null;
+        }
+        return localeExtensions.equals(((Locale)obj).localeExtensions);
+    }
+
+    // ================= privates =====================================
+
+    private transient BaseLocale baseLocale;
+    private transient LocaleExtensions localeExtensions;
+
+    /**
+     * Calculated hashcode
+     */
+    private transient volatile int hashCodeValue;
+
+    // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+    // private volatile static Locale defaultLocale = initDefault();
+    private static class NoImagePreloadHolder {
+        public volatile static Locale defaultLocale = initDefault();
+    }
+    private static volatile Locale defaultDisplayLocale;
+    private static volatile Locale defaultFormatLocale;
+
+    private transient volatile String languageTag;
+
+    // BEGIN Android-removed: Private helper getDisplayVariantArray() unused on Android.
+    /*
+    /**
+     * Return an array of the display names of the variant.
+     * @param inLocale The locale for which to retrieve the display variant.
+     * @return an array of display names, possible of zero length.
+     *
+    private String[] getDisplayVariantArray(Locale inLocale) {
+        // Split the variant name into tokens separated by '_'.
+        StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
+        String[] names = new String[tokenizer.countTokens()];
+
+        // For each variant token, lookup the display name.  If
+        // not found, use the variant name itself.
+        for (int i=0; i<names.length; ++i) {
+            names[i] = getDisplayString(tokenizer.nextToken(), null,
+                                inLocale, DISPLAY_VARIANT);
+        }
+
+        return names;
+    }
+    */
+    // END Android-removed: Private helper getDisplayVariantArray() unused on Android.
+
+    // BEGIN Android-removed: Private helper getDisplayKeyTypeExtensionString() unused on Android.
+    /*
+    private String getDisplayKeyTypeExtensionString(String key, LocaleResources lr, Locale inLocale) {
+        String type = localeExtensions.getUnicodeLocaleType(key);
+        String ret = getDisplayString(type, key, inLocale, DISPLAY_UEXT_TYPE);
+
+        if (ret == null || ret.equals(type)) {
+            // no localization for this type. try combining key/type separately
+            String displayType = type;
+            switch (key) {
+            case "cu":
+                displayType = lr.getCurrencyName(type.toLowerCase(Locale.ROOT));
+                break;
+            case "rg":
+                if (type != null &&
+                    // UN M.49 code should not be allowed here
+                    type.matches("^[a-zA-Z]{2}[zZ]{4}$")) {
+                        displayType = lr.getLocaleName(type.substring(0, 2).toUpperCase(Locale.ROOT));
+                }
+                break;
+            case "tz":
+                displayType = TimeZoneNameUtility.convertLDMLShortID(type)
+                    .map(id -> TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG, inLocale))
+                    .orElse(type);
+                break;
+            }
+            ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"),
+                getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY),
+                Optional.ofNullable(displayType).orElse(type));
+        }
+
+        return ret;
+    }
+    */
+    // END Android-removed: Private helper getDisplayKeyTypeExtensionString() unused on Android.
+
+    /**
+     * Format a list using given pattern strings.
+     * If either of the patterns is null, then a the list is
+     * formatted by concatenation with the delimiter ','.
+     * @param stringList the list of strings to be formatted.
+     * and formatting them into a list.
+     * @param pattern should take 2 arguments for reduction
+     * @return a string representing the list.
+     */
+    private static String formatList(String[] stringList, String pattern) {
+        // If we have no list patterns, compose the list in a simple,
+        // non-localized way.
+        if (pattern == null) {
+            return Arrays.stream(stringList).collect(Collectors.joining(","));
+        }
+
+        return switch (stringList.length) {
+            case 0 -> "";
+            case 1 -> stringList[0];
+            default -> Arrays.stream(stringList).reduce("",
+                (s1, s2) -> {
+                    if (s1.isEmpty()) {
+                        return s2;
+                    }
+                    if (s2.isEmpty()) {
+                        return s1;
+                    }
+                    return MessageFormat.format(pattern, s1, s2);
+                });
+        };
+    }
+
+    // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
+    // avoid its class loading.
+    private static boolean isUnicodeExtensionKey(String s) {
+        // 2alphanum
+        return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
+    }
+
+    /**
+     * @serialField language    String
+     *      language subtag in lower case.
+     *      (See <a href="java.base/java/util/Locale.html#getLanguage()">getLanguage()</a>)
+     * @serialField country     String
+     *      country subtag in upper case.
+     *      (See <a href="java.base/java/util/Locale.html#getCountry()">getCountry()</a>)
+     * @serialField variant     String
+     *      variant subtags separated by LOWLINE characters.
+     *      (See <a href="java.base/java/util/Locale.html#getVariant()">getVariant()</a>)
+     * @serialField hashcode    int
+     *      deprecated, for forward compatibility only
+     * @serialField script      String
+     *      script subtag in title case
+     *      (See <a href="java.base/java/util/Locale.html#getScript()">getScript()</a>)
+     * @serialField extensions  String
+     *      canonical representation of extensions, that is,
+     *      BCP47 extensions in alphabetical order followed by
+     *      BCP47 private use subtags, all in lower case letters
+     *      separated by HYPHEN-MINUS characters.
+     *      (See <a href="java.base/java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
+     *      <a href="java.base/java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
+     */
+    @java.io.Serial
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("language", String.class),
+        new ObjectStreamField("country", String.class),
+        new ObjectStreamField("variant", String.class),
+        new ObjectStreamField("hashcode", int.class),
+        new ObjectStreamField("script", String.class),
+        new ObjectStreamField("extensions", String.class),
+    };
+
+    /**
+     * Serializes this {@code Locale} to the specified {@code ObjectOutputStream}.
+     * @param out the {@code ObjectOutputStream} to write
+     * @throws IOException
+     * @since 1.7
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("language", baseLocale.getLanguage());
+        fields.put("script", baseLocale.getScript());
+        fields.put("country", baseLocale.getRegion());
+        fields.put("variant", baseLocale.getVariant());
+        fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
+        fields.put("hashcode", -1); // place holder just for backward support
+        out.writeFields();
+    }
+
+    /**
+     * Deserializes this {@code Locale}.
+     * @param in the {@code ObjectInputStream} to read
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @throws IllformedLocaleException
+     * @since 1.7
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        String language = (String)fields.get("language", "");
+        String script = (String)fields.get("script", "");
+        String country = (String)fields.get("country", "");
+        String variant = (String)fields.get("variant", "");
+        String extStr = (String)fields.get("extensions", "");
+
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
+        // Android-changed: Handle null for backwards compatible deserialization. http://b/26387905
+        // if (!extStr.isEmpty()) {
+        if (extStr != null && !extStr.isEmpty()) {
+            try {
+                InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+                bldr.setExtensions(extStr);
+                localeExtensions = bldr.getLocaleExtensions();
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage());
+            }
+        } else {
+            localeExtensions = null;
+        }
+    }
+
+    /**
+     * Returns a cached {@code Locale} instance equivalent to
+     * the deserialized {@code Locale}. When serialized
+     * language, country and variant fields read from the object data stream
+     * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
+     * fields are empty, this method supplies {@code UNICODE_LOCALE_EXTENSION}
+     * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
+     * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>
+     * for more information.
+     *
+     * @return an instance of {@code Locale} equivalent to
+     * the deserialized {@code Locale}.
+     * @throws java.io.ObjectStreamException
+     */
+    @java.io.Serial
+    private Object readResolve() throws java.io.ObjectStreamException {
+        return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
+                baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
+    }
+
+    private static volatile String[] isoLanguages;
+
+    private static volatile String[] isoCountries;
+
+    private static String convertOldISOCodes(String language) {
+        // we accept both the old and the new ISO codes for the languages whose ISO
+        // codes have changed, but we always store the NEW code, unless the property
+        // java.locale.useOldISOCodes is set to "true"
+        return BaseLocale.convertOldISOCodes(LocaleUtils.toLowerString(language).intern());
+    }
+
+    private static LocaleExtensions getCompatibilityExtensions(String language,
+                                                               String script,
+                                                               String country,
+                                                               String variant) {
+        LocaleExtensions extensions = null;
+        // Special cases for backward compatibility support
+        if (LocaleUtils.caseIgnoreMatch(language, "ja")
+                && script.isEmpty()
+                && LocaleUtils.caseIgnoreMatch(country, "jp")
+                && "JP".equals(variant)) {
+            // ja_JP_JP -> u-ca-japanese (calendar = japanese)
+            extensions = LocaleExtensions.CALENDAR_JAPANESE;
+        } else if (LocaleUtils.caseIgnoreMatch(language, "th")
+                && script.isEmpty()
+                && LocaleUtils.caseIgnoreMatch(country, "th")
+                && "TH".equals(variant)) {
+            // th_TH_TH -> u-nu-thai (numbersystem = thai)
+            extensions = LocaleExtensions.NUMBER_THAI;
+        }
+        return extensions;
+    }
+
+    // Android-removed: Drop nested private class LocaleNameGetter.
+    /*
+    /**
+     * Obtains a localized locale names from a LocaleNameProvider
+     * implementation.
+     *
+    private static class LocaleNameGetter
+        implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
+        private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
+
+        @Override
+        public String getObject(LocaleNameProvider localeNameProvider,
+                                Locale locale,
+                                String key,
+                                Object... params) {
+            assert params.length == 3;
+            int type = (Integer)params[0];
+            String code = (String)params[1];
+            String cat = (String)params[2];
+
+            switch(type) {
+            case DISPLAY_LANGUAGE:
+                return localeNameProvider.getDisplayLanguage(code, locale);
+            case DISPLAY_COUNTRY:
+                return localeNameProvider.getDisplayCountry(code, locale);
+            case DISPLAY_VARIANT:
+                return localeNameProvider.getDisplayVariant(code, locale);
+            case DISPLAY_SCRIPT:
+                return localeNameProvider.getDisplayScript(code, locale);
+            case DISPLAY_UEXT_KEY:
+                return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale);
+            case DISPLAY_UEXT_TYPE:
+                return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale);
+            default:
+                assert false; // shouldn't happen
+            }
+
+            return null;
+        }
+    }
+    */
+
+    /**
+     * Enum for locale categories.  These locale categories are used to get/set
+     * the default locale for the specific functionality represented by the
+     * category.
+     *
+     * @see #getDefault(Locale.Category)
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public enum Category {
+
+        /**
+         * Category used to represent the default locale for
+         * displaying user interfaces.
+         */
+        DISPLAY("user.language.display",
+                "user.script.display",
+                "user.country.display",
+                "user.variant.display",
+                "user.extensions.display"),
+
+        /**
+         * Category used to represent the default locale for
+         * formatting dates, numbers, and/or currencies.
+         */
+        FORMAT("user.language.format",
+               "user.script.format",
+               "user.country.format",
+               "user.variant.format",
+               "user.extensions.format");
+
+        Category(String languageKey, String scriptKey, String countryKey,
+                String variantKey, String extensionsKey) {
+            this.languageKey = languageKey;
+            this.scriptKey = scriptKey;
+            this.countryKey = countryKey;
+            this.variantKey = variantKey;
+            this.extensionsKey = extensionsKey;
+        }
+
+        final String languageKey;
+        final String scriptKey;
+        final String countryKey;
+        final String variantKey;
+        final String extensionsKey;
+    }
+
+    /**
+     * {@code Builder} is used to build instances of {@code Locale}
+     * from values configured by the setters.  Unlike the {@code Locale}
+     * constructors, the {@code Builder} checks if a value configured by a
+     * setter satisfies the syntax requirements defined by the {@code Locale}
+     * class.  A {@code Locale} object created by a {@code Builder} is
+     * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
+     * without losing information.
+     *
+     * <p><b>Note:</b> The {@code Locale} class does not provide any
+     * syntactic restrictions on variant, while BCP 47 requires each variant
+     * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
+     * alphanumerics.  The method {@code setVariant} throws
+     * {@code IllformedLocaleException} for a variant that does not satisfy
+     * this restriction. If it is necessary to support such a variant, use a
+     * Locale constructor.  However, keep in mind that a {@code Locale}
+     * object created this way might lose the variant information when
+     * transformed to a BCP 47 language tag.
+     *
+     * <p>The following example shows how to create a {@code Locale} object
+     * with the {@code Builder}.
+     * <blockquote>
+     * <pre>
+     *     Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
+     * </pre>
+     * </blockquote>
+     *
+     * <p>Builders can be reused; {@code clear()} resets all
+     * fields to their default values.
+     *
+     * @see Locale#forLanguageTag
+     * @since 1.7
+     */
+    public static final class Builder {
+        private final InternalLocaleBuilder localeBuilder;
+
+        /**
+         * Constructs an empty Builder. The default value of all
+         * fields, extensions, and private use information is the
+         * empty string.
+         */
+        public Builder() {
+            localeBuilder = new InternalLocaleBuilder();
+        }
+
+        /**
+         * Resets the {@code Builder} to match the provided
+         * {@code locale}.  Existing state is discarded.
+         *
+         * <p>All fields of the locale must be well-formed, see {@link Locale}.
+         *
+         * <p>Locales with any ill-formed fields cause
+         * {@code IllformedLocaleException} to be thrown, except for the
+         * following three cases which are accepted for compatibility
+         * reasons:<ul>
+         * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
+         * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
+         * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
+         *
+         * @param locale the locale
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code locale} has
+         * any ill-formed fields.
+         * @throws NullPointerException if {@code locale} is null.
+         */
+        public Builder setLocale(Locale locale) {
+            try {
+                localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the Builder to match the provided IETF BCP 47
+         * language tag.  Discards the existing state.  Null and the
+         * empty string cause the builder to be reset, like {@link
+         * #clear}.  Legacy tags (see {@link
+         * Locale#forLanguageTag}) are converted to their canonical
+         * form before being processed.  Otherwise, the language tag
+         * must be well-formed (see {@link Locale}) or an exception is
+         * thrown (unlike {@code Locale.forLanguageTag}, which
+         * just discards ill-formed and following portions of the
+         * tag).
+         *
+         * @param languageTag the language tag
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code languageTag} is ill-formed
+         * @see Locale#forLanguageTag(String)
+         */
+        public Builder setLanguageTag(String languageTag) {
+            ParseStatus sts = new ParseStatus();
+            LanguageTag tag = LanguageTag.parse(languageTag, sts);
+            if (sts.isError()) {
+                throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
+            }
+            localeBuilder.setLanguageTag(tag);
+            return this;
+        }
+
+        /**
+         * Sets the language.  If {@code language} is the empty string or
+         * null, the language in this {@code Builder} is removed.  Otherwise,
+         * the language must be <a href="./Locale.html#def_language">well-formed</a>
+         * or an exception is thrown.
+         *
+         * <p>The typical language value is a two or three-letter language
+         * code as defined in ISO639.
+         *
+         * @param language the language
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code language} is ill-formed
+         */
+        public Builder setLanguage(String language) {
+            try {
+                localeBuilder.setLanguage(language);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the script. If {@code script} is null or the empty string,
+         * the script in this {@code Builder} is removed.
+         * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical script value is a four-letter script code as defined by ISO 15924.
+         *
+         * @param script the script
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code script} is ill-formed
+         */
+        public Builder setScript(String script) {
+            try {
+                localeBuilder.setScript(script);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the region.  If region is null or the empty string, the region
+         * in this {@code Builder} is removed.  Otherwise,
+         * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical region value is a two-letter ISO 3166 code or a
+         * three-digit UN M.49 area code.
+         *
+         * <p>The country value in the {@code Locale} created by the
+         * {@code Builder} is always normalized to upper case.
+         *
+         * @param region the region
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code region} is ill-formed
+         */
+        public Builder setRegion(String region) {
+            try {
+                localeBuilder.setRegion(region);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the variant.  If variant is null or the empty string, the
+         * variant in this {@code Builder} is removed.  Otherwise, it
+         * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
+         * subtags, or an exception is thrown.
+         *
+         * <p><b>Note:</b> This method checks if {@code variant}
+         * satisfies the IETF BCP 47 variant subtag's syntax requirements,
+         * and normalizes the value to lowercase letters.  However,
+         * the {@code Locale} class does not impose any syntactic
+         * restriction on variant, and the variant value in
+         * {@code Locale} is case sensitive.  To set such a variant,
+         * use a Locale constructor.
+         *
+         * @param variant the variant
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code variant} is ill-formed
+         */
+        public Builder setVariant(String variant) {
+            try {
+                localeBuilder.setVariant(variant);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the extension for the given key. If the value is null or the
+         * empty string, the extension is removed.  Otherwise, the extension
+         * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
+         * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
+         * Setting a value for this key replaces any existing Unicode locale key/type
+         * pairs with those defined in the extension.
+         *
+         * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
+         * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
+         * well-formed, the value for this key needs only to have subtags of one to
+         * eight alphanumeric characters, not two to eight as in the general case.
+         *
+         * @param key the extension key
+         * @param value the extension value
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code key} is illegal
+         * or {@code value} is ill-formed
+         * @see #setUnicodeLocaleKeyword(String, String)
+         */
+        public Builder setExtension(char key, String value) {
+            try {
+                localeBuilder.setExtension(key, value);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the Unicode locale keyword type for the given key.  If the type
+         * is null, the Unicode keyword is removed.  Otherwise, the key must be
+         * non-null and both key and type must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Keys and types are converted to lower case.
+         *
+         * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
+         * replaces all Unicode locale keywords with those defined in the
+         * extension.
+         *
+         * @param key the Unicode locale key
+         * @param type the Unicode locale type
+         * @return This builder.
+         * @throws IllformedLocaleException if {@code key} or {@code type}
+         * is ill-formed
+         * @throws NullPointerException if {@code key} is null
+         * @see #setExtension(char, String)
+         */
+        public Builder setUnicodeLocaleKeyword(String key, String type) {
+            try {
+                localeBuilder.setUnicodeLocaleKeyword(key, type);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Adds a unicode locale attribute, if not already present, otherwise
+         * has no effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if {@code attribute} is null
+         * @throws IllformedLocaleException if {@code attribute} is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder addUnicodeLocaleAttribute(String attribute) {
+            try {
+                localeBuilder.addUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Removes a unicode locale attribute, if present, otherwise has no
+         * effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Attribute comparison for removal is case-insensitive.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if {@code attribute} is null
+         * @throws IllformedLocaleException if {@code attribute} is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder removeUnicodeLocaleAttribute(String attribute) {
+            Objects.requireNonNull(attribute);
+            try {
+                localeBuilder.removeUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the builder to its initial, empty state.
+         *
+         * @return This builder.
+         */
+        public Builder clear() {
+            localeBuilder.clear();
+            return this;
+        }
+
+        /**
+         * Resets the extensions to their initial, empty state.
+         * Language, script, region and variant are unchanged.
+         *
+         * @return This builder.
+         * @see #setExtension(char, String)
+         */
+        public Builder clearExtensions() {
+            localeBuilder.clearExtensions();
+            return this;
+        }
+
+        /**
+         * Returns an instance of {@code Locale} created from the fields set
+         * on this builder.
+         *
+         * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
+         * when constructing a Locale. (Legacy tags are handled in
+         * {@link #setLanguageTag}.)
+         *
+         * @return A Locale.
+         */
+        public Locale build() {
+            BaseLocale baseloc = localeBuilder.getBaseLocale();
+            LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
+            if (extensions == null && !baseloc.getVariant().isEmpty()) {
+                extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
+                        baseloc.getRegion(), baseloc.getVariant());
+            }
+            return Locale.getInstance(baseloc, extensions);
+        }
+    }
+
+    /**
+     * This enum provides constants to select a filtering mode for locale
+     * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
+     * Matching of Language Tags</a> for details.
+     *
+     * <p>As an example, think of two Language Priority Lists each of which
+     * includes only one language range and a set of following language tags:
+     *
+     * <pre>
+     *    de (German)
+     *    de-DE (German, Germany)
+     *    de-Deva (German, in Devanagari script)
+     *    de-Deva-DE (German, in Devanagari script, Germany)
+     *    de-DE-1996 (German, Germany, orthography of 1996)
+     *    de-Latn-DE (German, in Latin script, Germany)
+     *    de-Latn-DE-1996 (German, in Latin script, Germany, orthography of 1996)
+     * </pre>
+     *
+     * The filtering method will behave as follows:
+     *
+     * <table class="striped">
+     * <caption>Filtering method behavior</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col">Filtering Mode</th>
+     * <th scope="col">Language Priority List: {@code "de-DE"}</th>
+     * <th scope="col">Language Priority List: {@code "de-*-DE"}</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row" style="vertical-align:top">
+     * {@link FilteringMode#AUTOSELECT_FILTERING AUTOSELECT_FILTERING}
+     * </th>
+     * <td style="vertical-align:top">
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td style="vertical-align:top">
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="vertical-align:top">
+     * {@link FilteringMode#EXTENDED_FILTERING EXTENDED_FILTERING}
+     * </th>
+     * <td style="vertical-align:top">
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * <td style="vertical-align:top">Same as above.</td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="vertical-align:top">
+     * {@link FilteringMode#IGNORE_EXTENDED_RANGES IGNORE_EXTENDED_RANGES}
+     * </th>
+     * <td style="vertical-align:top">
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td style="vertical-align:top">
+     * Performs <em>basic</em> filtering and returns {@code null} because
+     * nothing matches.
+     * </td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="vertical-align:top">
+     * {@link FilteringMode#MAP_EXTENDED_RANGES MAP_EXTENDED_RANGES}
+     * </th>
+     * <td style="vertical-align:top">Same as above.</td>
+     * <td style="vertical-align:top">
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"} because {@code "de-*-DE"} is mapped to
+     * {@code "de-DE"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="vertical-align:top">
+     * {@link FilteringMode#REJECT_EXTENDED_RANGES REJECT_EXTENDED_RANGES}
+     * </th>
+     * <td style="vertical-align:top">Same as above.</td>
+     * <td style="vertical-align:top">
+     * Throws {@link IllegalArgumentException} because {@code "de-*-DE"} is
+     * not a valid basic language range.
+     * </td>
+     * </tr>
+     * </tbody>
+     * </table>
+     *
+     * @see #filter(List, Collection, FilteringMode)
+     * @see #filterTags(List, Collection, FilteringMode)
+     *
+     * @since 1.8
+     */
+    public static enum FilteringMode {
+        /**
+         * Specifies automatic filtering mode based on the given Language
+         * Priority List consisting of language ranges. If all of the ranges
+         * are basic, basic filtering is selected. Otherwise, extended
+         * filtering is selected.
+         */
+        AUTOSELECT_FILTERING,
+
+        /**
+         * Specifies extended filtering.
+         */
+        EXTENDED_FILTERING,
+
+        /**
+         * Specifies basic filtering: Note that any extended language ranges
+         * included in the given Language Priority List are ignored.
+         */
+        IGNORE_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, they are mapped to the
+         * basic language range. Specifically, a language range starting with a
+         * subtag {@code "*"} is treated as a language range {@code "*"}. For
+         * example, {@code "*-US"} is treated as {@code "*"}. If {@code "*"} is
+         * not the first subtag, {@code "*"} and extra {@code "-"} are removed.
+         * For example, {@code "ja-*-JP"} is mapped to {@code "ja-JP"}.
+         */
+        MAP_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, the list is rejected
+         * and the filtering method throws {@link IllegalArgumentException}.
+         */
+        REJECT_EXTENDED_RANGES
+    };
+
+    /**
+     * This class expresses a <em>Language Range</em> defined in
+     * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+     * Language Tags</a>. A language range is an identifier which is used to
+     * select language tag(s) meeting specific requirements by using the
+     * mechanisms described in <a href="Locale.html#LocaleMatching">Locale
+     * Matching</a>. A list which represents a user's preferences and consists
+     * of language ranges is called a <em>Language Priority List</em>.
+     *
+     * <p>There are two types of language ranges: basic and extended. In RFC
+     * 4647, the syntax of language ranges is expressed in
+     * <a href="http://tools.ietf.org/html/rfc4234">ABNF</a> as follows:
+     * <blockquote>
+     * <pre>
+     *     basic-language-range    = (1*8ALPHA *("-" 1*8alphanum)) / "*"
+     *     extended-language-range = (1*8ALPHA / "*")
+     *                               *("-" (1*8alphanum / "*"))
+     *     alphanum                = ALPHA / DIGIT
+     * </pre>
+     * </blockquote>
+     * For example, {@code "en"} (English), {@code "ja-JP"} (Japanese, Japan),
+     * {@code "*"} (special language range which matches any language tag) are
+     * basic language ranges, whereas {@code "*-CH"} (any languages,
+     * Switzerland), {@code "es-*"} (Spanish, any regions), and
+     * {@code "zh-Hant-*"} (Traditional Chinese, any regions) are extended
+     * language ranges.
+     *
+     * @see #filter
+     * @see #filterTags
+     * @see #lookup
+     * @see #lookupTag
+     *
+     * @since 1.8
+     */
+    public static final class LanguageRange {
+
+       /**
+        * A constant holding the maximum value of weight, 1.0, which indicates
+        * that the language range is a good fit for the user.
+        */
+        public static final double MAX_WEIGHT = 1.0;
+
+       /**
+        * A constant holding the minimum value of weight, 0.0, which indicates
+        * that the language range is not a good fit for the user.
+        */
+        public static final double MIN_WEIGHT = 0.0;
+
+        private final String range;
+        private final double weight;
+
+        private volatile int hash;
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range}.
+         * Note that no validation is done against the IANA Language Subtag
+         * Registry at time of construction.
+         *
+         * <p>This is equivalent to {@code LanguageRange(range, MAX_WEIGHT)}.
+         *
+         * @param range a language range
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         * @throws IllegalArgumentException if the given {@code range} does not
+         * comply with the syntax of the language range mentioned in RFC 4647
+         */
+        public LanguageRange(String range) {
+            this(range, MAX_WEIGHT);
+        }
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range} and
+         * {@code weight}. Note that no validation is done against the IANA
+         * Language Subtag Registry at time of construction.
+         *
+         * @param range  a language range
+         * @param weight a weight value between {@code MIN_WEIGHT} and
+         *     {@code MAX_WEIGHT}
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         * @throws IllegalArgumentException if the given {@code range} does not
+         * comply with the syntax of the language range mentioned in RFC 4647
+         * or if the given {@code weight} is less than {@code MIN_WEIGHT}
+         * or greater than {@code MAX_WEIGHT}
+         */
+        public LanguageRange(String range, double weight) {
+            if (range == null) {
+                throw new NullPointerException();
+            }
+            if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
+                throw new IllegalArgumentException("weight=" + weight);
+            }
+
+            range = range.toLowerCase(Locale.ROOT);
+
+            // Do syntax check.
+            boolean isIllFormed = false;
+            String[] subtags = range.split("-");
+            if (isSubtagIllFormed(subtags[0], true)
+                || range.endsWith("-")) {
+                isIllFormed = true;
+            } else {
+                for (int i = 1; i < subtags.length; i++) {
+                    if (isSubtagIllFormed(subtags[i], false)) {
+                        isIllFormed = true;
+                        break;
+                    }
+                }
+            }
+            if (isIllFormed) {
+                throw new IllegalArgumentException("range=" + range);
+            }
+
+            this.range = range;
+            this.weight = weight;
+        }
+
+        private static boolean isSubtagIllFormed(String subtag,
+                                                 boolean isFirstSubtag) {
+            if (subtag.isEmpty() || subtag.length() > 8) {
+                return true;
+            } else if (subtag.equals("*")) {
+                return false;
+            }
+            char[] charArray = subtag.toCharArray();
+            if (isFirstSubtag) { // ALPHA
+                for (char c : charArray) {
+                    if (c < 'a' || c > 'z') {
+                        return true;
+                    }
+                }
+            } else { // ALPHA / DIGIT
+                for (char c : charArray) {
+                    if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the language range of this {@code LanguageRange}.
+         *
+         * @return the language range.
+         */
+        public String getRange() {
+            return range;
+        }
+
+        /**
+         * Returns the weight of this {@code LanguageRange}.
+         *
+         * @return the weight value.
+         */
+        public double getWeight() {
+            return weight;
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority List.
+         *
+         * <p>This method performs a syntactic check for each language range in
+         * the given {@code ranges} but doesn't do validation using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>The {@code ranges} to be given can take one of the following
+         * forms:
+         *
+         * <pre>
+         *   "Accept-Language: ja,en;q=0.4"  (weighted list with Accept-Language prefix)
+         *   "ja,en;q=0.4"                   (weighted list)
+         *   "ja,en"                         (prioritized list)
+         * </pre>
+         *
+         * In a weighted list, each language range is given a weight value.
+         * The weight value is identical to the "quality value" in
+         * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>, and it
+         * expresses how much the user prefers  the language. A weight value is
+         * specified after a corresponding language range followed by
+         * {@code ";q="}, and the default weight value is {@code MAX_WEIGHT}
+         * when it is omitted.
+         *
+         * <p>Unlike a weighted list, language ranges in a prioritized list
+         * are sorted in the descending order based on its priority. The first
+         * language range has the highest priority and meets the user's
+         * preference most.
+         *
+         * <p>In either case, language ranges are sorted in descending order in
+         * the Language Priority List based on priority or weight. If a
+         * language range appears in the given {@code ranges} more than once,
+         * only the first one is included on the Language Priority List.
+         *
+         * <p>The returned list consists of language ranges from the given
+         * {@code ranges} and their equivalents found in the IANA Language
+         * Subtag Registry. For example, if the given {@code ranges} is
+         * {@code "Accept-Language: iw,en-us;q=0.7,en;q=0.3"}, the elements in
+         * the list to be returned are:
+         *
+         * <pre>
+         *  <b>Range</b>                                   <b>Weight</b>
+         *    "iw" (older tag for Hebrew)             1.0
+         *    "he" (new preferred code for Hebrew)    1.0
+         *    "en-us" (English, United States)        0.7
+         *    "en" (English)                          0.3
+         * </pre>
+         *
+         * Two language ranges, {@code "iw"} and {@code "he"}, have the same
+         * highest priority in the list. By adding {@code "he"} to the user's
+         * Language Priority List, locale-matching method can find Hebrew as a
+         * matching locale (or language tag) even if the application or system
+         * offers only {@code "he"} as a supported locale (or language tag).
+         *
+         * @param ranges a list of comma-separated language ranges or a list of
+         *     language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @return a Language Priority List consisting of language ranges
+         *     included in the given {@code ranges} and their equivalent
+         *     language ranges if available. The list is modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         */
+        public static List<LanguageRange> parse(String ranges) {
+            return LocaleMatcher.parse(ranges);
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority
+         * List, and then customizes the list using the given {@code map}.
+         * This method is equivalent to
+         * {@code mapEquivalents(parse(ranges), map)}.
+         *
+         * @param ranges a list of comma-separated language ranges or a list
+         *     of language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @param map a map containing information to customize language ranges
+         * @return a Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         * @see #parse(String)
+         * @see #mapEquivalents
+         */
+        public static List<LanguageRange> parse(String ranges,
+                                                Map<String, List<String>> map) {
+            return mapEquivalents(parse(ranges), map);
+        }
+
+        /**
+         * Generates a new customized Language Priority List using the given
+         * {@code priorityList} and {@code map}. If the given {@code map} is
+         * empty, this method returns a copy of the given {@code priorityList}.
+         *
+         * <p>In the map, a key represents a language range whereas a value is
+         * a list of equivalents of it. {@code '*'} cannot be used in the map.
+         * Each equivalent language range has the same weight value as its
+         * original language range.
+         *
+         * <pre>
+         *  An example of map:
+         *    <b>Key</b>                            <b>Value</b>
+         *      "zh" (Chinese)                 "zh",
+         *                                     "zh-Hans"(Simplified Chinese)
+         *      "zh-HK" (Chinese, Hong Kong)   "zh-HK"
+         *      "zh-TW" (Chinese, Taiwan)      "zh-TW"
+         * </pre>
+         *
+         * The customization is performed after modification using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>For example, if a user's Language Priority List consists of five
+         * language ranges ({@code "zh"}, {@code "zh-CN"}, {@code "en"},
+         * {@code "zh-TW"}, and {@code "zh-HK"}), the newly generated Language
+         * Priority List which is customized using the above map example will
+         * consists of {@code "zh"}, {@code "zh-Hans"}, {@code "zh-CN"},
+         * {@code "zh-Hans-CN"}, {@code "en"}, {@code "zh-TW"}, and
+         * {@code "zh-HK"}.
+         *
+         * <p>{@code "zh-HK"} and {@code "zh-TW"} aren't converted to
+         * {@code "zh-Hans-HK"} nor {@code "zh-Hans-TW"} even if they are
+         * included in the Language Priority List. In this example, mapping
+         * is used to clearly distinguish Simplified Chinese and Traditional
+         * Chinese.
+         *
+         * <p>If the {@code "zh"}-to-{@code "zh"} mapping isn't included in the
+         * map, a simple replacement will be performed and the customized list
+         * won't include {@code "zh"} and {@code "zh-CN"}.
+         *
+         * @param priorityList user's Language Priority List
+         * @param map a map containing information to customize language ranges
+         * @return a new Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code priorityList} is {@code null}
+         * @see #parse(String, Map)
+         */
+        public static List<LanguageRange> mapEquivalents(
+                                              List<LanguageRange>priorityList,
+                                              Map<String, List<String>> map) {
+            return LocaleMatcher.mapEquivalents(priorityList, map);
+        }
+
+        /**
+         * Returns a hash code value for the object.
+         *
+         * @return  a hash code value for this object.
+         */
+        @Override
+        public int hashCode() {
+            int h = hash;
+            if (h == 0) {
+                h = 17;
+                h = 37*h + range.hashCode();
+                long bitsWeight = Double.doubleToLongBits(weight);
+                h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32));
+                if (h != 0) {
+                    hash = h;
+                }
+            }
+            return h;
+        }
+
+        /**
+         * Compares this object to the specified object. The result is true if
+         * and only if the argument is not {@code null} and is a
+         * {@code LanguageRange} object that contains the same {@code range}
+         * and {@code weight} values as this object.
+         *
+         * @param obj the object to compare with
+         * @return  {@code true} if this object's {@code range} and
+         *     {@code weight} are the same as the {@code obj}'s; {@code false}
+         *     otherwise.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            return obj instanceof LanguageRange other
+                    && range.equals(other.range)
+                    && weight == other.weight;
+        }
+
+        /**
+         * Returns an informative string representation of this {@code LanguageRange}
+         * object, consisting of language range and weight if the range is
+         * weighted and the weight is less than the max weight.
+         *
+         * @return a string representation of this {@code LanguageRange} object.
+         */
+        @Override
+        public String toString() {
+            return (weight == MAX_WEIGHT) ? range : range + ";q=" + weight;
+        }
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647.
+     *
+     * This filter operation on the given {@code locales} ensures that only
+     * unique matching locale(s) are returned.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @param mode filtering mode
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales,
+                                      FilteringMode mode) {
+        return LocaleMatcher.filter(priorityList, locales, mode);
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filter(List, Collection, FilteringMode)} when {@code mode} is
+     * {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * This filter operation on the given {@code locales} ensures that only
+     * unique matching locale(s) are returned.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales) {
+        return filter(priorityList, locales, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647.
+     *
+     * This filter operation on the given {@code tags} ensures that only
+     * unique matching tag(s) are returned with preserved case. In case of
+     * duplicate matching tags with the case difference, the first matching
+     * tag with preserved case is returned.
+     * For example, "de-ch" is returned out of the duplicate matching tags
+     * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the
+     * given {@code tags}. Note that if the given {@code tags} is an unordered
+     * {@code Collection}, the returned matching tag out of duplicate tags is
+     * subject to change, depending on the implementation of the
+     * {@code Collection}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @param mode filtering mode
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags,
+                                          FilteringMode mode) {
+        return LocaleMatcher.filterTags(priorityList, tags, mode);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filterTags(List, Collection, FilteringMode)} when {@code mode}
+     * is {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * This filter operation on the given {@code tags} ensures that only
+     * unique matching tag(s) are returned with preserved case. In case of
+     * duplicate matching tags with the case difference, the first matching
+     * tag with preserved case is returned.
+     * For example, "de-ch" is returned out of the duplicate matching tags
+     * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the
+     * given {@code tags}. Note that if the given {@code tags} is an unordered
+     * {@code Collection}, the returned matching tag out of duplicate tags is
+     * subject to change, depending on the implementation of the
+     * {@code Collection}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags) {
+        return filterTags(priorityList, tags, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a {@code Locale} instance for the best-matching language
+     * tag using the lookup mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return the best matching {@code Locale} instance chosen based on
+     *     priority or weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static Locale lookup(List<LanguageRange> priorityList,
+                                Collection<Locale> locales) {
+        return LocaleMatcher.lookup(priorityList, locales);
+    }
+
+    /**
+     * Returns the best-matching language tag using the lookup mechanism
+     * defined in RFC 4647.
+     *
+     * This lookup operation on the given {@code tags} ensures that the
+     * first matching tag with preserved case is returned.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tangs used for matching
+     * @return the best matching language tag chosen based on priority or
+     *     weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static String lookupTag(List<LanguageRange> priorityList,
+                                   Collection<String> tags) {
+        return LocaleMatcher.lookupTag(priorityList, tags);
+    }
+
+}
diff --git a/android-35/java/util/LocaleISOData.java b/android-35/java/util/LocaleISOData.java
new file mode 100644
index 0000000..9dd9e83
--- /dev/null
+++ b/android-35/java/util/LocaleISOData.java
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+class LocaleISOData {
+    /**
+     * The 2- and 3-letter ISO 639 language codes.
+     */
+    static final String isoLanguageTable =
+          "aa" + "aar"  // Afar
+        + "ab" + "abk"  // Abkhazian
+        + "ae" + "ave"  // Avestan
+        + "af" + "afr"  // Afrikaans
+        + "ak" + "aka"  // Akan
+        + "am" + "amh"  // Amharic
+        + "an" + "arg"  // Aragonese
+        + "ar" + "ara"  // Arabic
+        + "as" + "asm"  // Assamese
+        + "av" + "ava"  // Avaric
+        + "ay" + "aym"  // Aymara
+        + "az" + "aze"  // Azerbaijani
+        + "ba" + "bak"  // Bashkir
+        + "be" + "bel"  // Belarusian
+        + "bg" + "bul"  // Bulgarian
+        + "bh" + "bih"  // Bihari
+        + "bi" + "bis"  // Bislama
+        + "bm" + "bam"  // Bambara
+        + "bn" + "ben"  // Bengali
+        + "bo" + "bod"  // Tibetan
+        + "br" + "bre"  // Breton
+        + "bs" + "bos"  // Bosnian
+        + "ca" + "cat"  // Catalan
+        + "ce" + "che"  // Chechen
+        + "ch" + "cha"  // Chamorro
+        + "co" + "cos"  // Corsican
+        + "cr" + "cre"  // Cree
+        + "cs" + "ces"  // Czech
+        + "cu" + "chu"  // Church Slavic
+        + "cv" + "chv"  // Chuvash
+        + "cy" + "cym"  // Welsh
+        + "da" + "dan"  // Danish
+        + "de" + "deu"  // German
+        + "dv" + "div"  // Divehi
+        + "dz" + "dzo"  // Dzongkha
+        + "ee" + "ewe"  // Ewe
+        + "el" + "ell"  // Greek
+        + "en" + "eng"  // English
+        + "eo" + "epo"  // Esperanto
+        + "es" + "spa"  // Spanish
+        + "et" + "est"  // Estonian
+        + "eu" + "eus"  // Basque
+        + "fa" + "fas"  // Persian
+        + "ff" + "ful"  // Fulah
+        + "fi" + "fin"  // Finnish
+        + "fj" + "fij"  // Fijian
+        + "fo" + "fao"  // Faroese
+        + "fr" + "fra"  // French
+        + "fy" + "fry"  // Frisian
+        + "ga" + "gle"  // Irish
+        + "gd" + "gla"  // Scottish Gaelic
+        + "gl" + "glg"  // Gallegan
+        + "gn" + "grn"  // Guarani
+        + "gu" + "guj"  // Gujarati
+        + "gv" + "glv"  // Manx
+        + "ha" + "hau"  // Hausa
+        + "he" + "heb"  // Hebrew
+        + "hi" + "hin"  // Hindi
+        + "ho" + "hmo"  // Hiri Motu
+        + "hr" + "hrv"  // Croatian
+        + "ht" + "hat"  // Haitian
+        + "hu" + "hun"  // Hungarian
+        + "hy" + "hye"  // Armenian
+        + "hz" + "her"  // Herero
+        + "ia" + "ina"  // Interlingua
+        + "id" + "ind"  // Indonesian
+        + "ie" + "ile"  // Interlingue
+        + "ig" + "ibo"  // Igbo
+        + "ii" + "iii"  // Sichuan Yi
+        + "ik" + "ipk"  // Inupiaq
+        + "in" + "ind"  // Indonesian (old)
+        + "io" + "ido"  // Ido
+        + "is" + "isl"  // Icelandic
+        + "it" + "ita"  // Italian
+        + "iu" + "iku"  // Inuktitut
+        + "iw" + "heb"  // Hebrew (old)
+        + "ja" + "jpn"  // Japanese
+        + "ji" + "yid"  // Yiddish (old)
+        + "jv" + "jav"  // Javanese
+        + "ka" + "kat"  // Georgian
+        + "kg" + "kon"  // Kongo
+        + "ki" + "kik"  // Kikuyu
+        + "kj" + "kua"  // Kwanyama
+        + "kk" + "kaz"  // Kazakh
+        + "kl" + "kal"  // Greenlandic
+        + "km" + "khm"  // Khmer
+        + "kn" + "kan"  // Kannada
+        + "ko" + "kor"  // Korean
+        + "kr" + "kau"  // Kanuri
+        + "ks" + "kas"  // Kashmiri
+        + "ku" + "kur"  // Kurdish
+        + "kv" + "kom"  // Komi
+        + "kw" + "cor"  // Cornish
+        + "ky" + "kir"  // Kirghiz
+        + "la" + "lat"  // Latin
+        + "lb" + "ltz"  // Luxembourgish
+        + "lg" + "lug"  // Ganda
+        + "li" + "lim"  // Limburgish
+        + "ln" + "lin"  // Lingala
+        + "lo" + "lao"  // Lao
+        + "lt" + "lit"  // Lithuanian
+        + "lu" + "lub"  // Luba-Katanga
+        + "lv" + "lav"  // Latvian
+        + "mg" + "mlg"  // Malagasy
+        + "mh" + "mah"  // Marshallese
+        + "mi" + "mri"  // Maori
+        + "mk" + "mkd"  // Macedonian
+        + "ml" + "mal"  // Malayalam
+        + "mn" + "mon"  // Mongolian
+        + "mo" + "mol"  // Moldavian
+        + "mr" + "mar"  // Marathi
+        + "ms" + "msa"  // Malay
+        + "mt" + "mlt"  // Maltese
+        + "my" + "mya"  // Burmese
+        + "na" + "nau"  // Nauru
+        + "nb" + "nob"  // Norwegian Bokm?l
+        + "nd" + "nde"  // North Ndebele
+        + "ne" + "nep"  // Nepali
+        + "ng" + "ndo"  // Ndonga
+        + "nl" + "nld"  // Dutch
+        + "nn" + "nno"  // Norwegian Nynorsk
+        + "no" + "nor"  // Norwegian
+        + "nr" + "nbl"  // South Ndebele
+        + "nv" + "nav"  // Navajo
+        + "ny" + "nya"  // Nyanja
+        + "oc" + "oci"  // Occitan
+        + "oj" + "oji"  // Ojibwa
+        + "om" + "orm"  // Oromo
+        + "or" + "ori"  // Oriya
+        + "os" + "oss"  // Ossetian
+        + "pa" + "pan"  // Panjabi
+        + "pi" + "pli"  // Pali
+        + "pl" + "pol"  // Polish
+        + "ps" + "pus"  // Pushto
+        + "pt" + "por"  // Portuguese
+        + "qu" + "que"  // Quechua
+        + "rm" + "roh"  // Raeto-Romance
+        + "rn" + "run"  // Rundi
+        + "ro" + "ron"  // Romanian
+        + "ru" + "rus"  // Russian
+        + "rw" + "kin"  // Kinyarwanda
+        + "sa" + "san"  // Sanskrit
+        + "sc" + "srd"  // Sardinian
+        + "sd" + "snd"  // Sindhi
+        + "se" + "sme"  // Northern Sami
+        + "sg" + "sag"  // Sango
+        + "si" + "sin"  // Sinhalese
+        + "sk" + "slk"  // Slovak
+        + "sl" + "slv"  // Slovenian
+        + "sm" + "smo"  // Samoan
+        + "sn" + "sna"  // Shona
+        + "so" + "som"  // Somali
+        + "sq" + "sqi"  // Albanian
+        + "sr" + "srp"  // Serbian
+        + "ss" + "ssw"  // Swati
+        + "st" + "sot"  // Southern Sotho
+        + "su" + "sun"  // Sundanese
+        + "sv" + "swe"  // Swedish
+        + "sw" + "swa"  // Swahili
+        + "ta" + "tam"  // Tamil
+        + "te" + "tel"  // Telugu
+        + "tg" + "tgk"  // Tajik
+        + "th" + "tha"  // Thai
+        + "ti" + "tir"  // Tigrinya
+        + "tk" + "tuk"  // Turkmen
+        + "tl" + "tgl"  // Tagalog
+        + "tn" + "tsn"  // Tswana
+        + "to" + "ton"  // Tonga
+        + "tr" + "tur"  // Turkish
+        + "ts" + "tso"  // Tsonga
+        + "tt" + "tat"  // Tatar
+        + "tw" + "twi"  // Twi
+        + "ty" + "tah"  // Tahitian
+        + "ug" + "uig"  // Uighur
+        + "uk" + "ukr"  // Ukrainian
+        + "ur" + "urd"  // Urdu
+        + "uz" + "uzb"  // Uzbek
+        + "ve" + "ven"  // Venda
+        + "vi" + "vie"  // Vietnamese
+        + "vo" + "vol"  // Volap?k
+        + "wa" + "wln"  // Walloon
+        + "wo" + "wol"  // Wolof
+        + "xh" + "xho"  // Xhosa
+        + "yi" + "yid"  // Yiddish
+        + "yo" + "yor"  // Yoruba
+        + "za" + "zha"  // Zhuang
+        + "zh" + "zho"  // Chinese
+        + "zu" + "zul"  // Zulu
+        ;
+
+    /**
+     * The 2- and 3-letter ISO 3166 country codes.
+     */
+    static final String isoCountryTable =
+          "AD" + "AND"  // Andorra, Principality of
+        + "AE" + "ARE"  // United Arab Emirates
+        + "AF" + "AFG"  // Afghanistan
+        + "AG" + "ATG"  // Antigua and Barbuda
+        + "AI" + "AIA"  // Anguilla
+        + "AL" + "ALB"  // Albania, People's Socialist Republic of
+        + "AM" + "ARM"  // Armenia
+//      + "AN" + "ANT"  // Netherlands Antilles
+        + "AO" + "AGO"  // Angola, Republic of
+        + "AQ" + "ATA"  // Antarctica (the territory South of 60 deg S)
+        + "AR" + "ARG"  // Argentina, Argentine Republic
+        + "AS" + "ASM"  // American Samoa
+        + "AT" + "AUT"  // Austria, Republic of
+        + "AU" + "AUS"  // Australia, Commonwealth of
+        + "AW" + "ABW"  // Aruba
+        + "AX" + "ALA"  // \u00c5land Islands
+        + "AZ" + "AZE"  // Azerbaijan, Republic of
+        + "BA" + "BIH"  // Bosnia and Herzegovina
+        + "BB" + "BRB"  // Barbados
+        + "BD" + "BGD"  // Bangladesh, People's Republic of
+        + "BE" + "BEL"  // Belgium, Kingdom of
+        + "BF" + "BFA"  // Burkina Faso
+        + "BG" + "BGR"  // Bulgaria, People's Republic of
+        + "BH" + "BHR"  // Bahrain, Kingdom of
+        + "BI" + "BDI"  // Burundi, Republic of
+        + "BJ" + "BEN"  // Benin, People's Republic of
+        + "BL" + "BLM"  // Saint Barth\u00e9lemy
+        + "BM" + "BMU"  // Bermuda
+        + "BN" + "BRN"  // Brunei Darussalam
+        + "BO" + "BOL"  // Bolivia, Republic of
+        + "BQ" + "BES"  // Bonaire, Sint Eustatius and Saba
+        + "BR" + "BRA"  // Brazil, Federative Republic of
+        + "BS" + "BHS"  // Bahamas, Commonwealth of the
+        + "BT" + "BTN"  // Bhutan, Kingdom of
+        + "BV" + "BVT"  // Bouvet Island (Bouvetoya)
+        + "BW" + "BWA"  // Botswana, Republic of
+        + "BY" + "BLR"  // Belarus
+        + "BZ" + "BLZ"  // Belize
+        + "CA" + "CAN"  // Canada
+        + "CC" + "CCK"  // Cocos (Keeling) Islands
+        + "CD" + "COD"  // Congo, Democratic Republic of
+        + "CF" + "CAF"  // Central African Republic
+        + "CG" + "COG"  // Congo, People's Republic of
+        + "CH" + "CHE"  // Switzerland, Swiss Confederation
+        + "CI" + "CIV"  // Cote D'Ivoire, Ivory Coast, Republic of the
+        + "CK" + "COK"  // Cook Islands
+        + "CL" + "CHL"  // Chile, Republic of
+        + "CM" + "CMR"  // Cameroon, United Republic of
+        + "CN" + "CHN"  // China, People's Republic of
+        + "CO" + "COL"  // Colombia, Republic of
+        + "CR" + "CRI"  // Costa Rica, Republic of
+//      + "CS" + "SCG"  // Serbia and Montenegro
+        + "CU" + "CUB"  // Cuba, Republic of
+        + "CV" + "CPV"  // Cape Verde, Republic of
+        + "CW" + "CUW"  // Cura\u00e7ao
+        + "CX" + "CXR"  // Christmas Island
+        + "CY" + "CYP"  // Cyprus, Republic of
+        + "CZ" + "CZE"  // Czech Republic
+        + "DE" + "DEU"  // Germany
+        + "DJ" + "DJI"  // Djibouti, Republic of
+        + "DK" + "DNK"  // Denmark, Kingdom of
+        + "DM" + "DMA"  // Dominica, Commonwealth of
+        + "DO" + "DOM"  // Dominican Republic
+        + "DZ" + "DZA"  // Algeria, People's Democratic Republic of
+        + "EC" + "ECU"  // Ecuador, Republic of
+        + "EE" + "EST"  // Estonia
+        + "EG" + "EGY"  // Egypt, Arab Republic of
+        + "EH" + "ESH"  // Western Sahara
+        + "ER" + "ERI"  // Eritrea
+        + "ES" + "ESP"  // Spain, Spanish State
+        + "ET" + "ETH"  // Ethiopia
+        + "FI" + "FIN"  // Finland, Republic of
+        + "FJ" + "FJI"  // Fiji, Republic of the Fiji Islands
+        + "FK" + "FLK"  // Falkland Islands (Malvinas)
+        + "FM" + "FSM"  // Micronesia, Federated States of
+        + "FO" + "FRO"  // Faeroe Islands
+        + "FR" + "FRA"  // France, French Republic
+        + "GA" + "GAB"  // Gabon, Gabonese Republic
+        + "GB" + "GBR"  // United Kingdom of Great Britain & N. Ireland
+        + "GD" + "GRD"  // Grenada
+        + "GE" + "GEO"  // Georgia
+        + "GF" + "GUF"  // French Guiana
+        + "GG" + "GGY"  // Guernsey
+        + "GH" + "GHA"  // Ghana, Republic of
+        + "GI" + "GIB"  // Gibraltar
+        + "GL" + "GRL"  // Greenland
+        + "GM" + "GMB"  // Gambia, Republic of the
+        + "GN" + "GIN"  // Guinea, Revolutionary People's Rep'c of
+        + "GP" + "GLP"  // Guadaloupe
+        + "GQ" + "GNQ"  // Equatorial Guinea, Republic of
+        + "GR" + "GRC"  // Greece, Hellenic Republic
+        + "GS" + "SGS"  // South Georgia and the South Sandwich Islands
+        + "GT" + "GTM"  // Guatemala, Republic of
+        + "GU" + "GUM"  // Guam
+        + "GW" + "GNB"  // Guinea-Bissau, Republic of
+        + "GY" + "GUY"  // Guyana, Republic of
+        + "HK" + "HKG"  // Hong Kong, Special Administrative Region of China
+        + "HM" + "HMD"  // Heard and McDonald Islands
+        + "HN" + "HND"  // Honduras, Republic of
+        + "HR" + "HRV"  // Hrvatska (Croatia)
+        + "HT" + "HTI"  // Haiti, Republic of
+        + "HU" + "HUN"  // Hungary, Hungarian People's Republic
+        + "ID" + "IDN"  // Indonesia, Republic of
+        + "IE" + "IRL"  // Ireland
+        + "IL" + "ISR"  // Israel, State of
+        + "IM" + "IMN"  // Isle of Man
+        + "IN" + "IND"  // India, Republic of
+        + "IO" + "IOT"  // British Indian Ocean Territory (Chagos Archipelago)
+        + "IQ" + "IRQ"  // Iraq, Republic of
+        + "IR" + "IRN"  // Iran, Islamic Republic of
+        + "IS" + "ISL"  // Iceland, Republic of
+        + "IT" + "ITA"  // Italy, Italian Republic
+        + "JE" + "JEY"  // Jersey
+        + "JM" + "JAM"  // Jamaica
+        + "JO" + "JOR"  // Jordan, Hashemite Kingdom of
+        + "JP" + "JPN"  // Japan
+        + "KE" + "KEN"  // Kenya, Republic of
+        + "KG" + "KGZ"  // Kyrgyz Republic
+        + "KH" + "KHM"  // Cambodia, Kingdom of
+        + "KI" + "KIR"  // Kiribati, Republic of
+        + "KM" + "COM"  // Comoros, Union of the
+        + "KN" + "KNA"  // St. Kitts and Nevis
+        + "KP" + "PRK"  // Korea, Democratic People's Republic of
+        + "KR" + "KOR"  // Korea, Republic of
+        + "KW" + "KWT"  // Kuwait, State of
+        + "KY" + "CYM"  // Cayman Islands
+        + "KZ" + "KAZ"  // Kazakhstan, Republic of
+        + "LA" + "LAO"  // Lao People's Democratic Republic
+        + "LB" + "LBN"  // Lebanon, Lebanese Republic
+        + "LC" + "LCA"  // St. Lucia
+        + "LI" + "LIE"  // Liechtenstein, Principality of
+        + "LK" + "LKA"  // Sri Lanka, Democratic Socialist Republic of
+        + "LR" + "LBR"  // Liberia, Republic of
+        + "LS" + "LSO"  // Lesotho, Kingdom of
+        + "LT" + "LTU"  // Lithuania
+        + "LU" + "LUX"  // Luxembourg, Grand Duchy of
+        + "LV" + "LVA"  // Latvia
+        + "LY" + "LBY"  // Libyan Arab Jamahiriya
+        + "MA" + "MAR"  // Morocco, Kingdom of
+        + "MC" + "MCO"  // Monaco, Principality of
+        + "MD" + "MDA"  // Moldova, Republic of
+        + "ME" + "MNE"  // Montenegro, Republic of
+        + "MF" + "MAF"  // Saint Martin
+        + "MG" + "MDG"  // Madagascar, Republic of
+        + "MH" + "MHL"  // Marshall Islands
+        + "MK" + "MKD"  // Macedonia, the former Yugoslav Republic of
+        + "ML" + "MLI"  // Mali, Republic of
+        + "MM" + "MMR"  // Myanmar
+        + "MN" + "MNG"  // Mongolia, Mongolian People's Republic
+        + "MO" + "MAC"  // Macao, Special Administrative Region of China
+        + "MP" + "MNP"  // Northern Mariana Islands
+        + "MQ" + "MTQ"  // Martinique
+        + "MR" + "MRT"  // Mauritania, Islamic Republic of
+        + "MS" + "MSR"  // Montserrat
+        + "MT" + "MLT"  // Malta, Republic of
+        + "MU" + "MUS"  // Mauritius
+        + "MV" + "MDV"  // Maldives, Republic of
+        + "MW" + "MWI"  // Malawi, Republic of
+        + "MX" + "MEX"  // Mexico, United Mexican States
+        + "MY" + "MYS"  // Malaysia
+        + "MZ" + "MOZ"  // Mozambique, People's Republic of
+        + "NA" + "NAM"  // Namibia
+        + "NC" + "NCL"  // New Caledonia
+        + "NE" + "NER"  // Niger, Republic of the
+        + "NF" + "NFK"  // Norfolk Island
+        + "NG" + "NGA"  // Nigeria, Federal Republic of
+        + "NI" + "NIC"  // Nicaragua, Republic of
+        + "NL" + "NLD"  // Netherlands, Kingdom of the
+        + "NO" + "NOR"  // Norway, Kingdom of
+        + "NP" + "NPL"  // Nepal, Kingdom of
+        + "NR" + "NRU"  // Nauru, Republic of
+        + "NU" + "NIU"  // Niue, Republic of
+        + "NZ" + "NZL"  // New Zealand
+        + "OM" + "OMN"  // Oman, Sultanate of
+        + "PA" + "PAN"  // Panama, Republic of
+        + "PE" + "PER"  // Peru, Republic of
+        + "PF" + "PYF"  // French Polynesia
+        + "PG" + "PNG"  // Papua New Guinea
+        + "PH" + "PHL"  // Philippines, Republic of the
+        + "PK" + "PAK"  // Pakistan, Islamic Republic of
+        + "PL" + "POL"  // Poland, Republic of Poland
+        + "PM" + "SPM"  // St. Pierre and Miquelon
+        + "PN" + "PCN"  // Pitcairn Island
+        + "PR" + "PRI"  // Puerto Rico
+        + "PS" + "PSE"  // Palestinian Territory, Occupied
+        + "PT" + "PRT"  // Portugal, Portuguese Republic
+        + "PW" + "PLW"  // Palau
+        + "PY" + "PRY"  // Paraguay, Republic of
+        + "QA" + "QAT"  // Qatar, State of
+        + "RE" + "REU"  // Reunion
+        + "RO" + "ROU"  // Romania, Socialist Republic of
+        + "RS" + "SRB"  // Serbia, Republic of
+        + "RU" + "RUS"  // Russian Federation
+        + "RW" + "RWA"  // Rwanda, Rwandese Republic
+        + "SA" + "SAU"  // Saudi Arabia, Kingdom of
+        + "SB" + "SLB"  // Solomon Islands
+        + "SC" + "SYC"  // Seychelles, Republic of
+        + "SD" + "SDN"  // Sudan, Democratic Republic of the
+        + "SE" + "SWE"  // Sweden, Kingdom of
+        + "SG" + "SGP"  // Singapore, Republic of
+        + "SH" + "SHN"  // St. Helena
+        + "SI" + "SVN"  // Slovenia
+        + "SJ" + "SJM"  // Svalbard & Jan Mayen Islands
+        + "SK" + "SVK"  // Slovakia (Slovak Republic)
+        + "SL" + "SLE"  // Sierra Leone, Republic of
+        + "SM" + "SMR"  // San Marino, Republic of
+        + "SN" + "SEN"  // Senegal, Republic of
+        + "SO" + "SOM"  // Somalia, Somali Republic
+        + "SR" + "SUR"  // Suriname, Republic of
+        + "SS" + "SSD"  // South Sudan
+        + "ST" + "STP"  // Sao Tome and Principe, Democratic Republic of
+        + "SV" + "SLV"  // El Salvador, Republic of
+        + "SX" + "SXM"  // Sint Maarten (Dutch part)
+        + "SY" + "SYR"  // Syrian Arab Republic
+        + "SZ" + "SWZ"  // Swaziland, Kingdom of
+        + "TC" + "TCA"  // Turks and Caicos Islands
+        + "TD" + "TCD"  // Chad, Republic of
+        + "TF" + "ATF"  // French Southern Territories
+        + "TG" + "TGO"  // Togo, Togolese Republic
+        + "TH" + "THA"  // Thailand, Kingdom of
+        + "TJ" + "TJK"  // Tajikistan
+        + "TK" + "TKL"  // Tokelau (Tokelau Islands)
+        + "TL" + "TLS"  // Timor-Leste, Democratic Republic of
+        + "TM" + "TKM"  // Turkmenistan
+        + "TN" + "TUN"  // Tunisia, Republic of
+        + "TO" + "TON"  // Tonga, Kingdom of
+        + "TR" + "TUR"  // Turkey, Republic of
+        + "TT" + "TTO"  // Trinidad and Tobago, Republic of
+        + "TV" + "TUV"  // Tuvalu
+        + "TW" + "TWN"  // Taiwan, Province of China
+        + "TZ" + "TZA"  // Tanzania, United Republic of
+        + "UA" + "UKR"  // Ukraine
+        + "UG" + "UGA"  // Uganda, Republic of
+        + "UM" + "UMI"  // United States Minor Outlying Islands
+        + "US" + "USA"  // United States of America
+        + "UY" + "URY"  // Uruguay, Eastern Republic of
+        + "UZ" + "UZB"  // Uzbekistan
+        + "VA" + "VAT"  // Holy See (Vatican City State)
+        + "VC" + "VCT"  // St. Vincent and the Grenadines
+        + "VE" + "VEN"  // Venezuela, Bolivarian Republic of
+        + "VG" + "VGB"  // British Virgin Islands
+        + "VI" + "VIR"  // US Virgin Islands
+        + "VN" + "VNM"  // Viet Nam, Socialist Republic of
+        + "VU" + "VUT"  // Vanuatu
+        + "WF" + "WLF"  // Wallis and Futuna Islands
+        + "WS" + "WSM"  // Samoa, Independent State of
+        + "YE" + "YEM"  // Yemen
+        + "YT" + "MYT"  // Mayotte
+        + "ZA" + "ZAF"  // South Africa, Republic of
+        + "ZM" + "ZMB"  // Zambia, Republic of
+        + "ZW" + "ZWE"  // Zimbabwe
+        ;
+
+    /**
+     * Array to hold country codes for ISO3166-3.
+     */
+    static final String[] ISO3166_3 = {
+        "AIDJ", "ANHH", "BQAQ", "BUMM", "BYAA", "CSHH", "CSXX", "CTKI", "DDDE",
+        "DYBJ", "FQHH", "FXFR", "GEHH", "HVBF", "JTUM", "MIUM", "NHVU", "NQAQ",
+        "NTHH", "PCHH", "PUUM", "PZPA", "RHZW", "SKIN", "SUHH", "TPTL", "VDVN",
+        "WKUM", "YDYE", "YUCS", "ZRCD"
+    };
+
+    /**
+     * This method computes a set of ISO3166-1 alpha-3 country codes from
+     * existing isoCountryTable.
+     */
+    static Set<String> computeISO3166_1Alpha3Countries() {
+        int tableLength = isoCountryTable.length();
+        String[] isoTable = new String[tableLength / 5];
+        for (int i = 0, index = 0; index < tableLength; i++, index += 5) {
+            isoTable[i] = isoCountryTable.substring(index + 2, index + 5);
+        }
+        return Set.of(isoTable);
+    }
+
+    private LocaleISOData() {
+    }
+}
diff --git a/android-35/java/util/LongSummaryStatistics.java b/android-35/java/util/LongSummaryStatistics.java
new file mode 100644
index 0000000..ec8d944
--- /dev/null
+++ b/android-35/java/util/LongSummaryStatistics.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of longs with:
+ * <pre> {@code
+ * LongSummaryStatistics stats = longStream.collect(LongSummaryStatistics::new,
+ *                                                  LongSummaryStatistics::accept,
+ *                                                  LongSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code LongSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * LongSummaryStatistics stats = people.stream()
+ *                                     .collect(Collectors.summarizingLong(Person::getAge));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their ages.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingLong(java.util.function.ToLongFunction)
+ * Collectors.summarizingLong()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the count or the sum.
+ * @since 1.8
+ */
+public class LongSummaryStatistics implements LongConsumer, IntConsumer {
+    private long count;
+    private long sum;
+    private long min = Long.MAX_VALUE;
+    private long max = Long.MIN_VALUE;
+
+    /**
+     * Constructs an empty instance with zero count, zero sum,
+     * {@code Long.MAX_VALUE} min, {@code Long.MIN_VALUE} max and zero
+     * average.
+     */
+    public LongSummaryStatistics() { }
+
+    /**
+     * Constructs a non-empty instance with the specified {@code count},
+     * {@code min}, {@code max}, and {@code sum}.
+     *
+     * <p>If {@code count} is zero then the remaining arguments are ignored and
+     * an empty instance is constructed.
+     *
+     * <p>If the arguments are inconsistent then an {@code IllegalArgumentException}
+     * is thrown.  The necessary consistent argument conditions are:
+     * <ul>
+     *   <li>{@code count >= 0}</li>
+     *   <li>{@code min <= max}</li>
+     * </ul>
+     * @apiNote
+     * The enforcement of argument correctness means that the retrieved set of
+     * recorded values obtained from a {@code LongSummaryStatistics} source
+     * instance may not be a legal set of arguments for this constructor due to
+     * arithmetic overflow of the source's recorded count of values.
+     * The consistent argument conditions are not sufficient to prevent the
+     * creation of an internally inconsistent instance.  An example of such a
+     * state would be an instance with: {@code count} = 2, {@code min} = 1,
+     * {@code max} = 2, and {@code sum} = 0.
+     *
+     * @param count the count of values
+     * @param min the minimum value
+     * @param max the maximum value
+     * @param sum the sum of all values
+     * @throws IllegalArgumentException if the arguments are inconsistent
+     * @since 10
+     */
+    public LongSummaryStatistics(long count, long min, long max, long sum)
+            throws IllegalArgumentException {
+        if (count < 0L) {
+            throw new IllegalArgumentException("Negative count value");
+        } else if (count > 0L) {
+            if (min > max) throw new IllegalArgumentException("Minimum greater than maximum");
+
+            this.count = count;
+            this.sum = sum;
+            this.min = min;
+            this.max = max;
+        }
+        // Use default field values if count == 0
+    }
+
+    /**
+     * Records a new {@code int} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        accept((long) value);
+    }
+
+    /**
+     * Records a new {@code long} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(long value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code LongSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code LongSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(LongSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Long.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Long.MAX_VALUE} if none
+     */
+    public final long getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Long.MIN_VALUE} if no
+     * values have been recorded
+     *
+     * @return the maximum value, or {@code Long.MIN_VALUE} if none
+     */
+    public final long getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return The arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    /**
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    @Override
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/android-35/java/util/Map.java b/android-35/java/util/Map.java
new file mode 100644
index 0000000..c44b51a
--- /dev/null
+++ b/android-35/java/util/Map.java
@@ -0,0 +1,1737 @@
+/*
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.io.Serializable;
+
+/**
+ * An object that maps keys to values.  A map cannot contain duplicate keys;
+ * each key can map to at most one value.
+ *
+ * <p>This interface takes the place of the {@code Dictionary} class, which
+ * was a totally abstract class rather than an interface.
+ *
+ * <p>The {@code Map} interface provides three <i>collection views</i>, which
+ * allow a map's contents to be viewed as a set of keys, collection of values,
+ * or set of key-value mappings.  The <i>order</i> of a map is defined as
+ * the order in which the iterators on the map's collection views return their
+ * elements.  Some map implementations, like the {@code TreeMap} class, make
+ * specific guarantees as to their order; others, like the {@code HashMap}
+ * class, do not.
+ *
+ * <p>Note: great care must be exercised if mutable objects are used as map
+ * keys.  The behavior of a map is not specified if the value of an object is
+ * changed in a manner that affects {@code equals} comparisons while the
+ * object is a key in the map.  A special case of this prohibition is that it
+ * is not permissible for a map to contain itself as a key.  While it is
+ * permissible for a map to contain itself as a value, extreme caution is
+ * advised: the {@code equals} and {@code hashCode} methods are no longer
+ * well defined on such a map.
+ *
+ * <p>All general-purpose map implementation classes should provide two
+ * "standard" constructors: a void (no arguments) constructor which creates an
+ * empty map, and a constructor with a single argument of type {@code Map},
+ * which creates a new map with the same key-value mappings as its argument.
+ * In effect, the latter constructor allows the user to copy any map,
+ * producing an equivalent map of the desired class.  There is no way to
+ * enforce this recommendation (as interfaces cannot contain constructors) but
+ * all of the general-purpose map implementations in the JDK comply.
+ *
+ * <p>The "destructive" methods contained in this interface, that is, the
+ * methods that modify the map on which they operate, are specified to throw
+ * {@code UnsupportedOperationException} if this map does not support the
+ * operation.  If this is the case, these methods may, but are not required
+ * to, throw an {@code UnsupportedOperationException} if the invocation would
+ * have no effect on the map.  For example, invoking the {@link #putAll(Map)}
+ * method on an unmodifiable map may, but is not required to, throw the
+ * exception if the map whose mappings are to be "superimposed" is empty.
+ *
+ * <p>Some map implementations have restrictions on the keys and values they
+ * may contain.  For example, some implementations prohibit null keys and
+ * values, and some have restrictions on the types of their keys.  Attempting
+ * to insert an ineligible key or value throws an unchecked exception,
+ * typically {@code NullPointerException} or {@code ClassCastException}.
+ * Attempting to query the presence of an ineligible key or value may throw an
+ * exception, or it may simply return false; some implementations will exhibit
+ * the former behavior and some will exhibit the latter.  More generally,
+ * attempting an operation on an ineligible key or value whose completion
+ * would not result in the insertion of an ineligible element into the map may
+ * throw an exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined
+ * in terms of the {@link Object#equals(Object) equals} method.  For
+ * example, the specification for the {@link #containsKey(Object)
+ * containsKey(Object key)} method says: "returns {@code true} if and
+ * only if this map contains a mapping for a key {@code k} such that
+ * {@code (key==null ? k==null : key.equals(k))}." This specification should
+ * <i>not</i> be construed to imply that invoking {@code Map.containsKey}
+ * with a non-null argument {@code key} will cause {@code key.equals(k)} to
+ * be invoked for any key {@code k}.  Implementations are free to
+ * implement optimizations whereby the {@code equals} invocation is avoided,
+ * for example, by first comparing the hash codes of the two keys.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some map operations which perform recursive traversal of the map may fail
+ * with an exception for self-referential instances where the map directly or
+ * indirectly contains itself. This includes the {@code clone()},
+ * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
+ * Implementations may optionally handle the self-referential scenario, however
+ * most current implementations do not do so.
+ *
+ * <h2><a id="unmodifiable">Unmodifiable Maps</a></h2>
+ * <p>The {@link Map#of() Map.of},
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, and
+ * {@link Map#copyOf Map.copyOf}
+ * static factory methods provide a convenient way to create unmodifiable maps.
+ * The {@code Map}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Keys and values
+ * cannot be added, removed, or updated. Calling any mutator method on the Map
+ * will always cause {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained keys or values are themselves mutable, this may cause the
+ * Map to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} keys and values. Attempts to create them with
+ * {@code null} keys or values result in {@code NullPointerException}.
+ * <li>They are serializable if all keys and values are serializable.
+ * <li>They reject duplicate keys at creation time. Duplicate keys
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of mappings is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions
+ * about the identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see HashMap
+ * @see TreeMap
+ * @see Hashtable
+ * @see SortedMap
+ * @see Collection
+ * @see Set
+ * @since 1.2
+ */
+public interface Map<K, V> {
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.  If the
+     * map contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.  More formally, returns {@code true} if and only if
+     * this map contains a mapping for a key {@code k} such that
+     * {@code Objects.equals(key, k)}.  (There can be
+     * at most one such mapping.)
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified
+     *         key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsKey(Object key);
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such that
+     * {@code Objects.equals(value, v)}.  This operation
+     * will probably require time linear in the map size for most
+     * implementations of the {@code Map} interface.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws ClassCastException if the value is of an inappropriate type for
+     *         this map
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified value is null and this
+     *         map does not permit null values
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsValue(Object value);
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that
+     * {@code Objects.equals(key, k)},
+     * then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} does not <i>necessarily</i> indicate that the map
+     * contains no mapping for the key; it's also possible that the map
+     * explicitly maps the key to {@code null}.  The {@link #containsKey
+     * containsKey} operation may be used to distinguish these two cases.
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    V get(Object key);
+
+    // Modification Operations
+
+    /**
+     * Associates the specified value with the specified key in this map
+     * (optional operation).  If the map previously contained a mapping for
+     * the key, the old value is replaced by the specified value.  (A map
+     * {@code m} is said to contain a mapping for a key {@code k} if and only
+     * if {@link #containsKey(Object) m.containsKey(k)} would return
+     * {@code true}.)
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key},
+     *         if the implementation supports {@code null} values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V put(K key, V value);
+
+    /**
+     * Removes the mapping for a key from this map if it is present
+     * (optional operation).   More formally, if this map contains a mapping
+     * from key {@code k} to value {@code v} such that
+     * {@code Objects.equals(key, k)}, that mapping
+     * is removed.  (The map can contain at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or {@code null} if the map contained no mapping for the key.
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} does not <i>necessarily</i> indicate that the map
+     * contained no mapping for the key; it's also possible that the map
+     * explicitly mapped the key to {@code null}.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this
+     *         map does not permit null keys
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    V remove(Object key);
+
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * (optional operation).  The effect of this call is equivalent to that
+     * of calling {@link #put(Object,Object) put(k, v)} on this map once
+     * for each mapping from key {@code k} to value {@code v} in the
+     * specified map.  The behavior of this operation is undefined if the
+     * specified map is modified while the operation is in progress.
+     *
+     * @param m mappings to be stored in this map
+     * @throws UnsupportedOperationException if the {@code putAll} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a key or value in the
+     *         specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null, or if
+     *         this map does not permit null keys or values, and the
+     *         specified map contains null keys or values
+     * @throws IllegalArgumentException if some property of a key or value in
+     *         the specified map prevents it from being stored in this map
+     */
+    void putAll(Map<? extends K, ? extends V> m);
+
+    /**
+     * Removes all of the mappings from this map (optional operation).
+     * The map will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this map
+     */
+    void clear();
+
+
+    // Views
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    Set<Map.Entry<K, V>> entrySet();
+
+    /**
+     * A map entry (key-value pair). The Entry may be unmodifiable, or the
+     * value may be modifiable if the optional {@code setValue} method is
+     * implemented. The Entry may be independent of any map, or it may represent
+     * an entry of the entry-set view of a map.
+     * <p>
+     * Instances of the {@code Map.Entry} interface may be obtained by iterating
+     * the entry-set view of a map. These instances maintain a connection to the
+     * original, backing map. This connection to the backing map is valid
+     * <i>only</i> for the duration of iteration over the entry-set view.
+     * During iteration of the entry-set view, if supported by the backing map,
+     * a change to a {@code Map.Entry}'s value via the
+     * {@link Map.Entry#setValue setValue} method will be visible in the backing map.
+     * The behavior of such a {@code Map.Entry} instance is undefined outside of
+     * iteration of the map's entry-set view. It is also undefined if the backing
+     * map has been modified after the {@code Map.Entry} was returned by the
+     * iterator, except through the {@code Map.Entry.setValue} method. In particular,
+     * a change to the value of a mapping in the backing map might or might not be
+     * visible in the corresponding {@code Map.Entry} element of the entry-set view.
+     *
+     * @apiNote
+     * It is possible to create a {@code Map.Entry} instance that is disconnected
+     * from a backing map by using the {@link Map.Entry#copyOf copyOf} method. For example,
+     * the following creates a snapshot of a map's entries that is guaranteed not to
+     * change even if the original map is modified:
+     * <pre> {@code
+     * var entries = map.entrySet().stream().map(Map.Entry::copyOf).toList()
+     * }</pre>
+     *
+     * @see Map#entrySet()
+     * @since 1.2
+     */
+    interface Entry<K, V> {
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        K getKey();
+
+        /**
+         * Returns the value corresponding to this entry.  If the mapping
+         * has been removed from the backing map (by the iterator's
+         * {@code remove} operation), the results of this call are undefined.
+         *
+         * @return the value corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V getValue();
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  (Writes through to the map.)  The
+         * behavior of this call is undefined if the mapping has already been
+         * removed from the map (by the iterator's {@code remove} operation).
+         *
+         * @param value new value to be stored in this entry
+         * @return old value corresponding to the entry
+         * @throws UnsupportedOperationException if the {@code put} operation
+         *         is not supported by the backing map
+         * @throws ClassCastException if the class of the specified value
+         *         prevents it from being stored in the backing map
+         * @throws NullPointerException if the backing map does not permit
+         *         null values, and the specified value is null
+         * @throws IllegalArgumentException if some property of this value
+         *         prevents it from being stored in the backing map
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V setValue(V value);
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *     (e1.getKey()==null ?
+         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &amp;&amp;
+         *     (e1.getValue()==null ?
+         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
+         * </pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         */
+        boolean equals(Object o);
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
+         * </pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@code Object.hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see Object#hashCode()
+         * @see Object#equals(Object)
+         * @see #equals(Object)
+         */
+        int hashCode();
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on key.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with a null key.
+         *
+         * @param  <K> the {@link Comparable} type of then map keys
+         * @param  <V> the type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on key.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on value.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with null values.
+         *
+         * @param <K> the type of the map keys
+         * @param <V> the {@link Comparable} type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on value.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by key using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the key {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the key.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by value using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the value {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the value.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
+        }
+
+        /**
+         * Returns a copy of the given {@code Map.Entry}. The returned instance is not
+         * associated with any map. The returned instance has the same characteristics
+         * as instances returned by the {@link Map#entry Map::entry} method.
+         *
+         * @apiNote
+         * An instance obtained from a map's entry-set view has a connection to that map.
+         * The {@code copyOf}  method may be used to create a {@code Map.Entry} instance,
+         * containing the same key and value, that is independent of any map.
+         *
+         * @implNote
+         * If the given entry was obtained from a call to {@code copyOf} or {@code Map::entry},
+         * calling {@code copyOf} will generally not create another copy.
+         *
+         * @param <K> the type of the key
+         * @param <V> the type of the value
+         * @param e the entry to be copied
+         * @return a map entry equal to the given entry
+         * @throws NullPointerException if e is null or if either of its key or value is null
+         * @since 17
+         */
+        @SuppressWarnings("unchecked")
+        public static <K, V> Map.Entry<K, V> copyOf(Map.Entry<? extends K, ? extends V> e) {
+            Objects.requireNonNull(e);
+            if (e instanceof KeyValueHolder) {
+                return (Map.Entry<K, V>) e;
+            } else {
+                return Map.entry(e.getKey(), e.getValue());
+            }
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps {@code m1} and
+     * {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the
+     * {@code equals} method works properly across different implementations
+     * of the {@code Map} interface.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * {@code entrySet()} view.  This ensures that {@code m1.equals(m2)}
+     * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
+     * {@code m1} and {@code m2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+    // Defaultable methods
+
+    /**
+     * Returns the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key.
+     *
+     * @implSpec
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the default mapping of the key
+     * @return the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     * this map
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     * does not permit null keys
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (((v = get(key)) != null) || containsKey(key))
+            ? v
+            : defaultValue;
+    }
+
+    /**
+     * Performs the given action for each entry in this map until all entries
+     * have been processed or the action throws an exception.   Unless
+     * otherwise specified by the implementing class, actions are performed in
+     * the order of entry set iteration (if an iteration order is specified.)
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }</pre>
+     *
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param action The action to be performed for each entry
+     * @throws NullPointerException if the specified action is null
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * Replaces each entry's value with the result of invoking the given
+     * function on that entry until all entries have been processed or the
+     * function throws an exception.  Exceptions thrown by the function are
+     * relayed to the caller.
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param function the function to apply to each entry
+     * @throws UnsupportedOperationException if the {@code set} operation
+     * is not supported by this map's entry set iterator.
+     * @throws ClassCastException if the class of a replacement value
+     * prevents it from being stored in this map
+     * @throws NullPointerException if the specified function is null, or the
+     * specified replacement value is null, and this map does not permit null
+     * values
+     * @throws ClassCastException if a replacement value is of an inappropriate
+     *         type for this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if function or a replacement value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a replacement value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+
+            // ise thrown from function is not a cme.
+            v = function.apply(k, v);
+
+            try {
+                entry.setValue(v);
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}) associates it with the given value and returns
+     * {@code null}, else returns the current value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * V v = map.get(key);
+     * if (v == null)
+     *     v = map.put(key, value);
+     *
+     * return v;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="{@docRoot}/java.base/java/util/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
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V putIfAbsent(K key, V value) {
+        V v = get(key);
+        if (v == null) {
+            v = put(key, value);
+        }
+
+        return v;
+    }
+
+    /**
+     * Removes the entry for the specified key only if it is currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.remove(key);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="{@docRoot}/java.base/java/util/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
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default boolean remove(Object key, Object value) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, value) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        remove(key);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
+     *     map.put(key, newValue);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * The default implementation does not throw NullPointerException
+     * for maps that do not support null values if oldValue is null unless
+     * newValue is also null.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or newValue is null,
+     *         and this map does not permit null keys or values
+     * @throws NullPointerException if oldValue is null and this map does not
+     *         permit null values
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default boolean replace(K key, V oldValue, V newValue) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, oldValue) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        put(key, newValue);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if it is
+     * currently mapped to some value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key)) {
+     *     return map.put(key, value);
+     * } else
+     *     return null;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/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
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default V replace(K key, V value) {
+        V curValue;
+        if (((curValue = get(key)) != null) || containsKey(key)) {
+            curValue = put(key, value);
+        }
+        return curValue;
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}), attempts to compute its value using the given mapping
+     * function and enters it into this map unless {@code null}.
+     *
+     * <p>If the mapping function returns {@code null}, no mapping is recorded.
+     * If the mapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and no mapping is recorded.  The most
+     * common usage is to construct a new object serving as an initial
+     * mapped value or memoized result, as in:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new Value(f(k)));
+     * }</pre>
+     *
+     * <p>Or to implement a multi-value map, {@code Map<K,Collection<V>>},
+     * supporting multiple values per key:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
+     * }</pre>
+     *
+     * <p>The mapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}, then returning the current value or {@code null} if now
+     * absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) == null) {
+     *     V newValue = mappingFunction.apply(key);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * mapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * mapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * mapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the mapping function is applied once atomically only if the value
+     * is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the mapping function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the mappingFunction
+     *         is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V v;
+        if ((v = get(key)) == null) {
+            V newValue;
+            if ((newValue = mappingFunction.apply(key)) != null) {
+                put(key, newValue);
+                return newValue;
+            }
+        }
+
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present and non-null, attempts to
+     * compute a new mapping given the key and its current mapped value.
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if now absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) != null) {
+     *     V oldValue = map.get(key);
+     *     V newValue = remappingFunction.apply(key, oldValue);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     *     else
+     *         map.remove(key);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue;
+        if ((oldValue = get(key)) != null) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if (newValue != null) {
+                put(key, newValue);
+                return newValue;
+            } else {
+                remove(key);
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its current
+     * mapped value (or {@code null} if there is no current mapping). For
+     * example, to either create or append a {@code String} msg to a value
+     * mapping:
+     *
+     * <pre> {@code
+     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
+     * (Method {@link #merge merge()} is often simpler to use for such purposes.)
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed
+     * (or remains absent if initially absent).  If the remapping function
+     * itself throws an (unchecked) exception, the exception is rethrown, and
+     * the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = remappingFunction.apply(key, oldValue);
+     * if (newValue != null) {
+     *     map.put(key, newValue);
+     * } else if (oldValue != null || map.containsKey(key)) {
+     *     map.remove(key);
+     * }
+     * return newValue;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V compute(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue = get(key);
+
+        V newValue = remappingFunction.apply(key, oldValue);
+        if (newValue == null) {
+            // delete mapping
+            if (oldValue != null || containsKey(key)) {
+                // something to remove
+                remove(key);
+                return null;
+            } else {
+                // nothing to do. Leave things as they were.
+                return null;
+            }
+        } else {
+            // add or replace old mapping
+            put(key, newValue);
+            return newValue;
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value or is
+     * associated with null, associates it with the given non-null value.
+     * Otherwise, replaces the associated value with the results of the given
+     * remapping function, or removes if the result is {@code null}. This
+     * method may be of use when combining multiple mapped values for a key.
+     * For example, to either create or append a {@code String msg} to a
+     * value mapping:
+     *
+     * <pre> {@code
+     * map.merge(key, msg, String::concat)
+     * }</pre>
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if absent:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = (oldValue == null) ? value :
+     *              remappingFunction.apply(oldValue, value);
+     * if (newValue == null)
+     *     map.remove(key);
+     * else
+     *     map.put(key, newValue);
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the resulting value is to be associated
+     * @param value the non-null value to be merged with the existing value
+     *        associated with the key or, if no existing value or a null value
+     *        is associated with the key, to be associated with the key
+     * @param remappingFunction the remapping function to recompute a value if
+     *        present
+     * @return the new value associated with the specified key, or null if no
+     *         value is associated with the key
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not support null keys or the value or remappingFunction is
+     *         null
+     * @since 1.8
+     */
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        V oldValue = get(key);
+        V newValue = (oldValue == null) ? value :
+                   remappingFunction.apply(oldValue, value);
+        if (newValue == null) {
+            remove(key);
+        } else {
+            put(key, newValue);
+        }
+        return newValue;
+    }
+
+    /**
+     * Returns an unmodifiable map containing zero mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    @SuppressWarnings("unchecked")
+    static <K, V> Map<K, V> of() {
+        return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
+    }
+
+    /**
+     * Returns an unmodifiable map containing a single mapping.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1) {
+        return new ImmutableCollections.Map1<>(k1, v1);
+    }
+
+    /**
+     * Returns an unmodifiable map containing two mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
+    }
+
+    /**
+     * Returns an unmodifiable map containing three mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
+    }
+
+    /**
+     * Returns an unmodifiable map containing four mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
+    }
+
+    /**
+     * Returns an unmodifiable map containing five mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+    }
+
+    /**
+     * Returns an unmodifiable map containing six mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6);
+    }
+
+    /**
+     * Returns an unmodifiable map containing seven mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7);
+    }
+
+    /**
+     * Returns an unmodifiable map containing eight mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8);
+    }
+
+    /**
+     * Returns an unmodifiable map containing nine mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9);
+    }
+
+    /**
+     * Returns an unmodifiable map containing ten mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
+    }
+
+    /**
+     * Returns an unmodifiable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * <pre>{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map<Integer,String> map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }</pre>
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any entry, key, or value is {@code null}, or if
+     *         the {@code entries} array is {@code null}
+     *
+     * @see Map#entry Map.entry()
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
+        if (entries.length == 0) { // implicit null check of entries array
+            @SuppressWarnings("unchecked")
+            var map = (Map<K,V>) ImmutableCollections.EMPTY_MAP;
+            return map;
+        } else if (entries.length == 1) {
+            // implicit null check of the array slot
+            return new ImmutableCollections.Map1<>(entries[0].getKey(),
+                    entries[0].getValue());
+        } else {
+            Object[] kva = new Object[entries.length << 1];
+            int a = 0;
+            for (Entry<? extends K, ? extends V> entry : entries) {
+                // implicit null checks of each array slot
+                kva[a++] = entry.getKey();
+                kva[a++] = entry.getValue();
+            }
+            return new ImmutableCollections.MapN<>(kva);
+        }
+    }
+
+    /**
+     * Returns an unmodifiable {@link Entry} containing the given key and value.
+     * These entries are suitable for populating {@code Map} instances using the
+     * {@link Map#ofEntries Map.ofEntries()} method.
+     * The {@code Entry} instances created by this method have the following characteristics:
+     *
+     * <ul>
+     * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
+     * key or value result in {@code NullPointerException}.
+     * <li>They are unmodifiable. Calls to {@link Entry#setValue Entry.setValue()}
+     * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
+     * <li>They are not serializable.
+     * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+     * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+     * as interchangeable and should not use them for synchronization, or
+     * unpredictable behavior may occur. For example, in a future release,
+     * synchronization may fail. Callers should make no assumptions
+     * about the identity of the returned instances. This method is free to
+     * create new instances or reuse existing ones.
+     * </ul>
+     *
+     * @apiNote
+     * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or
+     * {@link AbstractMap.SimpleImmutableEntry}.
+     *
+     * @param <K> the key's type
+     * @param <V> the value's type
+     * @param k the key
+     * @param v the value
+     * @return an {@code Entry} containing the specified key and value
+     * @throws NullPointerException if the key or value is {@code null}
+     *
+     * @see Map#ofEntries Map.ofEntries()
+     * @since 9
+     */
+    static <K, V> Entry<K, V> entry(K k, V v) {
+        // KeyValueHolder checks for nulls
+        return new KeyValueHolder<>(k, v);
+    }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable Map</a> containing the entries
+     * of the given Map. The given Map must not be null, and it must not contain any
+     * null keys or values. If the given Map is subsequently modified, the returned
+     * Map will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Map is an <a href="#unmodifiable">unmodifiable Map</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param map a {@code Map} from which entries are drawn, must be non-null
+     * @return a {@code Map} containing the entries of the given {@code Map}
+     * @throws NullPointerException if map is null, or if it contains any null keys or values
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes","unchecked"})
+    static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
+        if (map instanceof ImmutableCollections.AbstractImmutableMap) {
+            return (Map<K,V>)map;
+        } else {
+            return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
+        }
+    }
+}
diff --git a/android-35/java/util/MissingFormatArgumentException.java b/android-35/java/util/MissingFormatArgumentException.java
new file mode 100644
index 0000000..dcb0847
--- /dev/null
+++ b/android-35/java/util/MissingFormatArgumentException.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when there is a format specifier which does not
+ * have a corresponding argument or if an argument index refers to an argument
+ * that does not exist.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatArgumentException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 19190115L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unmatched format
+     * specifier.
+     *
+     * @param  s
+     *         Format specifier which does not have a corresponding argument
+     */
+    public MissingFormatArgumentException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unmatched format specifier.
+     *
+     * @return  The unmatched format specifier
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return "Format specifier '" + s + "'";
+    }
+}
diff --git a/android-35/java/util/MissingFormatWidthException.java b/android-35/java/util/MissingFormatWidthException.java
new file mode 100644
index 0000000..0ce9c3a
--- /dev/null
+++ b/android-35/java/util/MissingFormatWidthException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is required.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatWidthException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 15560123L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the specified format
+     * specifier.
+     *
+     * @param  s
+     *         The format specifier which does not have a width
+     */
+    public MissingFormatWidthException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the format specifier which does not have a width.
+     *
+     * @return  The format specifier which does not have a width
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return s;
+    }
+}
diff --git a/android-35/java/util/MissingResourceException.java b/android-35/java/util/MissingResourceException.java
new file mode 100644
index 0000000..ea93fd8
--- /dev/null
+++ b/android-35/java/util/MissingResourceException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+/**
+ * Signals that a resource is missing.
+ * @see java.lang.Exception
+ * @see ResourceBundle
+ * @author      Mark Davis
+ * @since       1.1
+ */
+public class MissingResourceException extends RuntimeException {
+
+    /**
+     * Constructs a MissingResourceException with the specified information.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     * @param className the name of the resource class
+     * @param key the key for the missing resource.
+     */
+    public MissingResourceException(String s, String className, String key) {
+        super(s);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Constructs a {@code MissingResourceException} with
+     * {@code message}, {@code className}, {@code key},
+     * and {@code cause}. This constructor is package private for
+     * use by {@code ResourceBundle.getBundle}.
+     *
+     * @param message
+     *        the detail message
+     * @param className
+     *        the name of the resource class
+     * @param key
+     *        the key for the missing resource.
+     * @param cause
+     *        the cause (which is saved for later retrieval by the
+     *        {@link Throwable.getCause()} method). (A null value is
+     *        permitted, and indicates that the cause is nonexistent
+     *        or unknown.)
+     */
+    MissingResourceException(String message, String className, String key, Throwable cause) {
+        super(message, cause);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the name of the resource class
+     */
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the key for the missing resource
+     */
+    public String getKey() {
+        return key;
+    }
+
+    //============ privates ============
+
+    // serialization compatibility with JDK1.1
+    @java.io.Serial
+    private static final long serialVersionUID = -4876345176062000401L;
+
+    /**
+     * The class name of the resource bundle requested by the user.
+     * @serial
+     */
+    private String className;
+
+    /**
+     * The name of the specific resource requested by the user.
+     * @serial
+     */
+    private String key;
+}
diff --git a/android-35/java/util/NavigableMap.java b/android-35/java/util/NavigableMap.java
new file mode 100644
index 0000000..98545ab
--- /dev/null
+++ b/android-35/java/util/NavigableMap.java
@@ -0,0 +1,448 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea 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/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link SortedMap} extended with navigation methods returning the
+ * closest matches for given search targets. Methods
+ * {@link #lowerEntry}, {@link #floorEntry}, {@link #ceilingEntry},
+ * and {@link #higherEntry} return {@code Map.Entry} objects
+ * associated with keys respectively less than, less than or equal,
+ * greater than or equal, and greater than a given key, returning
+ * {@code null} if there is no such key.  Similarly, methods
+ * {@link #lowerKey}, {@link #floorKey}, {@link #ceilingKey}, and
+ * {@link #higherKey} return only the associated keys. All of these
+ * methods are designed for locating, not traversing entries.
+ *
+ * <p>A {@code NavigableMap} may be accessed and traversed in either
+ * ascending or descending key order.  The {@link #descendingMap}
+ * method returns a view of the map with the senses of all relational
+ * and directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  Methods
+ * {@link #subMap(Object, boolean, Object, boolean) subMap(K, boolean, K, boolean)},
+ * {@link #headMap(Object, boolean) headMap(K, boolean)}, and
+ * {@link #tailMap(Object, boolean) tailMap(K, boolean)}
+ * differ from the like-named {@code SortedMap} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Submaps of any {@code NavigableMap}
+ * must implement the {@code NavigableMap} interface.
+ *
+ * <p>This interface additionally defines methods {@link #firstEntry},
+ * {@link #pollFirstEntry}, {@link #lastEntry}, and
+ * {@link #pollLastEntry} that return and/or remove the least and
+ * greatest mappings, if any exist, else returning {@code null}.
+ *
+ * <p>The methods
+ * {@link #ceilingEntry},
+ * {@link #firstEntry},
+ * {@link #floorEntry},
+ * {@link #higherEntry},
+ * {@link #lastEntry},
+ * {@link #lowerEntry},
+ * {@link #pollFirstEntry}, and
+ * {@link #pollLastEntry}
+ * return {@link Map.Entry} instances that represent snapshots of mappings as
+ * of the time of the call. They do <em>not</em> support mutation of the
+ * underlying map via the optional {@link Map.Entry#setValue setValue} method.
+ *
+ * <p>Methods
+ * {@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
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableMap}.  Similarly,
+ * {@link #keySet()} can be overridden to return {@link NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface NavigableMap<K,V> extends SortedMap<K,V> {
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> lowerEntry(K key);
+
+    /**
+     * Returns the greatest key strictly less than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K lowerKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> floorEntry(K key);
+
+    /**
+     * Returns the greatest key less than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K floorKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> ceilingEntry(K key);
+
+    /**
+     * Returns the least key greater than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K ceilingKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> higherEntry(K key);
+
+    /**
+     * Returns the least key strictly greater than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K higherKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the least key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> firstEntry();
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the greatest key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> lastEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed first entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollFirstEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed last entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollLastEntry();
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.  If either map is
+     * modified while an iteration over a collection view of either map
+     * is in progress (except through the iterator's own {@code remove}
+     * operation), the results of the iteration are undefined.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    NavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey} to {@code toKey}.  If {@code fromKey} and
+     * {@code toKey} are equal, the returned map is empty unless
+     * {@code fromInclusive} and {@code toInclusive} are both true.  The
+     * returned map is backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside of its range, or to construct a
+     * submap either of whose endpoints lie outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toKey high endpoint of the keys in the returned map
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey} to {@code toKey}
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                             K toKey,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are less than (or
+     * equal to, if {@code inclusive} is true) {@code toKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are greater than (or
+     * equal to, if {@code inclusive} is true) {@code fromKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are greater than
+     *         (or equal to, if {@code inclusive} is true) {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headMap(toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailMap(fromKey, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This method is equivalent to {@link #descendingMap descendingMap}.
+     *
+     * @implSpec
+     * The implementation in this interface returns the result of calling the
+     * {@code descendingMap} method.
+     *
+     * @return a reverse-ordered view of this map, as a {@code NavigableMap}
+     * @since 21
+     */
+    default NavigableMap<K, V> reversed() {
+        return this.descendingMap();
+    }
+}
diff --git a/android-35/java/util/NavigableSet.java b/android-35/java/util/NavigableSet.java
new file mode 100644
index 0000000..4dacd1e
--- /dev/null
+++ b/android-35/java/util/NavigableSet.java
@@ -0,0 +1,377 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea 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/publicdomain/zero/1.0/
+ */
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+package java.util;
+
+/**
+ * A {@link SortedSet} extended with navigation methods reporting
+ * closest matches for given search targets. Methods {@link #lower},
+ * {@link #floor}, {@link #ceiling}, and {@link #higher} return elements
+ * respectively less than, less than or equal, greater than or equal,
+ * and greater than a given element, returning {@code null} if there
+ * is no such element.
+ *
+ * <p>A {@code NavigableSet} may be accessed and traversed in either
+ * ascending or descending order.  The {@link #descendingSet} method
+ * returns a view of the set with the senses of all relational and
+ * directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  This interface additionally defines methods {@link
+ * #pollFirst} and {@link #pollLast} that return and remove the lowest
+ * and highest element, if one exists, else returning {@code null}.
+ * Methods
+ * {@link #subSet(Object, boolean, Object, boolean) subSet(E, boolean, E, boolean)},
+ * {@link #headSet(Object, boolean) headSet(E, boolean)}, and
+ * {@link #tailSet(Object, boolean) tailSet(E, boolean)}
+ * differ from the like-named {@code SortedSet} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Subsets of any {@code NavigableSet}
+ * must implement the {@code NavigableSet} interface.
+ *
+ * <p>The return values of navigation methods may be ambiguous in
+ * implementations that permit {@code null} elements. However, even
+ * in this case the result can be disambiguated by checking
+ * {@code contains(null)}. To avoid such issues, implementations of
+ * this interface are encouraged to <em>not</em> permit insertion of
+ * {@code null} elements. (Note that sorted sets of {@link
+ * Comparable} elements intrinsically do not permit {@code null}.)
+ *
+ * <p>Methods
+ * {@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
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public interface NavigableSet<E> extends SortedSet<E> {
+    /**
+     * Returns the greatest element in this set strictly less than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E lower(E e);
+
+    /**
+     * Returns the greatest element in this set less than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E floor(E e);
+
+    /**
+     * Returns the least element in this set greater than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E ceiling(E e);
+
+    /**
+     * Returns the least element in this set strictly greater than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E higher(E e);
+
+    /**
+     * Retrieves and removes the first (lowest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the first element, or {@code null} if this set is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last (highest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the last element, or {@code null} if this set is empty
+     */
+    E pollLast();
+
+    /**
+     * Returns an iterator over the elements in this set, in ascending order.
+     *
+     * @return an iterator over the elements in this set, in ascending order
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.  If either set is
+     * modified while an iteration over either set is in progress (except
+     * through the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    NavigableSet<E> descendingSet();
+
+    /**
+     * Returns an iterator over the elements in this set, in descending order.
+     * Equivalent in effect to {@code descendingSet().iterator()}.
+     *
+     * @return an iterator over the elements in this set, in descending order
+     */
+    Iterator<E> descendingIterator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range from
+     * {@code fromElement} to {@code toElement}.  If {@code fromElement} and
+     * {@code toElement} are equal, the returned set is empty unless {@code
+     * fromInclusive} and {@code toInclusive} are both true.  The returned set
+     * is backed by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all optional set
+     * operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toElement high endpoint of the returned set
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements range from
+     *         {@code fromElement}, inclusive, to {@code toElement}, exclusive
+     * @throws ClassCastException if {@code fromElement} and
+     *         {@code toElement} cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if {@code fromElement} or
+     *         {@code toElement} cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set does
+     *         not permit null elements
+     * @throws IllegalArgumentException if {@code fromElement} is
+     *         greater than {@code toElement}; or if this set itself
+     *         has a restricted range, and {@code fromElement} or
+     *         {@code toElement} lies outside the bounds of the range.
+     */
+    NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                           E toElement,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are less than
+     * (or equal to, if {@code inclusive} is true) {@code toElement}.  The
+     * returned set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint of the returned set
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toElement}
+     * @throws ClassCastException if {@code toElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code toElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code toElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> headSet(E toElement, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are greater
+     * than (or equal to, if {@code inclusive} is true) {@code fromElement}.
+     * The returned set is backed by this set, so changes in the returned set
+     * are reflected in this set, and vice-versa.  The returned set supports
+     * all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to {@code fromElement}
+     * @throws ClassCastException if {@code fromElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code fromElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code fromElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> tailSet(E fromElement, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headSet(toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailSet(fromElement, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> tailSet(E fromElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this set is not empty, the implementation in this interface returns the result of calling
+     * the {@code pollFirst} method. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeFirst() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.pollFirst();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * If this set is not empty, the implementation in this interface returns the result of calling
+     * the {@code pollLast} method. Otherwise, it throws {@code NoSuchElementException}.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeLast() {
+        if (this.isEmpty()) {
+            throw new NoSuchElementException();
+        } else {
+            return this.pollLast();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This method is equivalent to {@link #descendingSet descendingSet}.
+     *
+     * @implSpec
+     * The implementation in this interface returns the result of calling the
+     * {@code descendingSet} method.
+     *
+     * @return a reverse-ordered view of this collection, as a {@code NavigableSet}
+     * @since 21
+     */
+    default NavigableSet<E> reversed() {
+        return this.descendingSet();
+    }
+}
diff --git a/android-35/java/util/NoSuchElementException.java b/android-35/java/util/NoSuchElementException.java
new file mode 100644
index 0000000..28c2036
--- /dev/null
+++ b/android-35/java/util/NoSuchElementException.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by various accessor methods to indicate that the element being requested
+ * does not exist.
+ *
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Iterator#next()
+ * @since   1.0
+ */
+public class NoSuchElementException extends RuntimeException {
+    @java.io.Serial
+    private static final long serialVersionUID = 6769829250639411880L;
+
+    /**
+     * Constructs a {@code NoSuchElementException} with {@code null}
+     * as its error message string.
+     */
+    public NoSuchElementException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code NoSuchElementException} with the specified detail
+     * message and cause.
+     *
+     * @param s     the detail message, or null
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method), or null
+     * @since 15
+     */
+    public NoSuchElementException(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    /**
+     * Constructs a {@code NoSuchElementException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method)
+     * @since 15
+     */
+    public NoSuchElementException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code NoSuchElementException}, saving a reference
+     * to the error message string {@code s} for later retrieval by the
+     * {@code getMessage} method.
+     *
+     * @param   s   the detail message.
+     */
+    public NoSuchElementException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/Objects.java b/android-35/java/util/Objects.java
new file mode 100644
index 0000000..236011f
--- /dev/null
+++ b/android-35/java/util/Objects.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.util.Preconditions;
+
+import java.util.function.Supplier;
+
+/**
+ * This class consists of {@code static} utility methods for operating
+ * on objects, or checking certain conditions before operation.  These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out of bounds.
+ *
+ * @since 1.7
+ */
+public final class Objects {
+    private Objects() {
+        throw new AssertionError("No java.util.Objects instances for you!");
+    }
+
+    /**
+     * Returns {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise.
+     * Consequently, if both arguments are {@code null}, {@code true}
+     * is returned.  Otherwise, if the first argument is not {@code
+     * null}, equality is determined by calling the {@link
+     * Object#equals equals} method of the first argument with the
+     * second argument of this method. Otherwise, {@code false} is
+     * returned.
+     *
+     * @param a an object
+     * @param b an object to be compared with {@code a} for equality
+     * @return {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise
+     * @see Object#equals(Object)
+     */
+    public static boolean equals(Object a, Object b) {
+        return (a == b) || (a != null && a.equals(b));
+    }
+
+   /**
+    * Returns {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise.
+    *
+    * Two {@code null} values are deeply equal.  If both arguments are
+    * arrays, the algorithm in {@link Arrays#deepEquals(Object[],
+    * Object[]) Arrays.deepEquals} is used to determine equality.
+    * Otherwise, equality is determined by using the {@link
+    * Object#equals equals} method of the first argument.
+    *
+    * @param a an object
+    * @param b an object to be compared with {@code a} for deep equality
+    * @return {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise
+    * @see Arrays#deepEquals(Object[], Object[])
+    * @see Objects#equals(Object, Object)
+    */
+    public static boolean deepEquals(Object a, Object b) {
+        if (a == b)
+            return true;
+        else if (a == null || b == null)
+            return false;
+        else
+            return Arrays.deepEquals0(a, b);
+    }
+
+    /**
+     * Returns the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument.
+     *
+     * @param o an object
+     * @return the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument
+     * @see Object#hashCode
+     */
+    public static int hashCode(Object o) {
+        return o != null ? o.hashCode() : 0;
+    }
+
+   /**
+    * Generates a hash code for a sequence of input values. The hash
+    * code is generated as if all the input values were placed into an
+    * array, and that array were hashed by calling {@link
+    * Arrays#hashCode(Object[])}.
+    *
+    * <p>This method is useful for implementing {@link
+    * Object#hashCode()} on objects containing multiple fields. For
+    * example, if an object that has three fields, {@code x}, {@code
+    * y}, and {@code z}, one could write:
+    *
+    * <blockquote><pre>
+    * &#064;Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * </pre></blockquote>
+    *
+    * <b>Warning: When a single object reference is supplied, the returned
+    * value does not equal the hash code of that object reference.</b> This
+    * value can be computed by calling {@link #hashCode(Object)}.
+    *
+    * @param values the values to be hashed
+    * @return a hash value of the sequence of input values
+    * @see Arrays#hashCode(Object[])
+    * @see List#hashCode
+    */
+    public static int hash(Object... values) {
+        return Arrays.hashCode(values);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument.
+     *
+     * @param o an object
+     * @return the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument
+     * @see Object#toString
+     * @see String#valueOf(Object)
+     */
+    public static String toString(Object o) {
+        return String.valueOf(o);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} on the first
+     * argument if the first argument is not {@code null} and returns
+     * the second argument otherwise.
+     *
+     * @param o an object
+     * @param nullDefault string to return if the first argument is
+     *        {@code null}
+     * @return the result of calling {@code toString} on the first
+     * argument if it is not {@code null} and the second argument
+     * otherwise.
+     * @see Objects#toString(Object)
+     */
+    public static String toString(Object o, String nullDefault) {
+        return (o != null) ? o.toString() : nullDefault;
+    }
+
+    /**
+     * Returns 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * Consequently, if both arguments are {@code null} 0
+     * is returned.
+     *
+     * <p>Note that if one of the arguments is {@code null}, a {@code
+     * NullPointerException} may or may not be thrown depending on
+     * what ordering policy, if any, the {@link Comparator Comparator}
+     * chooses to have for {@code null} values.
+     *
+     * @param <T> the type of the objects being compared
+     * @param a an object
+     * @param b an object to be compared with {@code a}
+     * @param c the {@code Comparator} to compare the first two arguments
+     * @return 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * @see Comparable
+     * @see Comparator
+     */
+    public static <T> int compare(T a, T b, Comparator<? super T> c) {
+        return (a == b) ? 0 :  c.compare(a, b);
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null}. This
+     * method is designed primarily for doing parameter validation in methods
+     * and constructors, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar) {
+     *     this.bar = Objects.requireNonNull(bar);
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj the object reference to check for nullity
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        return obj;
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is. This method
+     * is designed primarily for doing parameter validation in methods and
+     * constructors with multiple parameters, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar, Baz baz) {
+     *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
+     *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj     the object reference to check for nullity
+     * @param message detail message to be used in the event that a {@code
+     *                NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj, String message) {
+        if (obj == null)
+            throw new NullPointerException(message);
+        return obj;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is {@code null} otherwise
+     * returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::isNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is {@code null} otherwise
+     * {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean isNull(Object obj) {
+        return obj == null;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is non-{@code null}
+     * otherwise returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::nonNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is non-{@code null}
+     * otherwise {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean nonNull(Object obj) {
+        return obj != null;
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and
+     * otherwise returns the non-{@code null} second argument.
+     *
+     * @param obj an object
+     * @param defaultObj a non-{@code null} object to return if the first argument
+     *                   is {@code null}
+     * @param <T> the type of the reference
+     * @return the first argument if it is non-{@code null} and
+     *        otherwise the second argument if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        {@code defaultObj} is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElse(T obj, T defaultObj) {
+        return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and otherwise
+     * returns the non-{@code null} value of {@code supplier.get()}.
+     *
+     * @param obj an object
+     * @param supplier of a non-{@code null} object to return if the first argument
+     *                 is {@code null}
+     * @param <T> the type of the first argument and return type
+     * @return the first argument if it is non-{@code null} and otherwise
+     *         the value from {@code supplier.get()} if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        either the {@code supplier} is {@code null} or
+     *        the {@code supplier.get()} value is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
+        return (obj != null) ? obj
+                : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is.
+     *
+     * <p>Unlike the method {@link #requireNonNull(Object, String)},
+     * this method allows creation of the message to be deferred until
+     * after the null check is made. While this may confer a
+     * performance advantage in the non-null case, when deciding to
+     * call this method care should be taken that the costs of
+     * creating the message supplier are less than the cost of just
+     * creating the string message directly.
+     *
+     * @param obj     the object reference to check for nullity
+     * @param messageSupplier supplier of the detail message to be
+     * used in the event that a {@code NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 1.8
+     */
+    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
+        if (obj == null)
+            throw new NullPointerException(messageSupplier == null ?
+                                           null : messageSupplier.get());
+        return obj;
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out of bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out of bounds
+     * @since 9
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    int checkIndex(int index, int length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out of bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+     * @since 9
+     */
+    public static
+    int checkFromToIndex(int fromIndex, int toIndex, int length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out of bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+     * @since 9
+     */
+    public static
+    int checkFromIndexSize(int fromIndex, int size, int length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out of bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out of bounds
+     * @since 16
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    long checkIndex(long index, long length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out of bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+     * @since 16
+     */
+    public static
+    long checkFromToIndex(long fromIndex, long toIndex, long length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out of bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out of bounds
+     * @since 16
+     */
+    public static
+    long checkFromIndexSize(long fromIndex, long size, long length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+}
diff --git a/android-35/java/util/Observable.java b/android-35/java/util/Observable.java
new file mode 100644
index 0000000..65e3995
--- /dev/null
+++ b/android-35/java/util/Observable.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class represents an observable object, or "data"
+ * in the model-view paradigm. It can be subclassed to represent an
+ * object that the application wants to have observed.
+ * <p>
+ * An observable object can have one or more observers. An observer
+ * may be any object that implements interface {@code Observer}. After an
+ * observable instance changes, an application calling the
+ * {@code Observable}'s {@code notifyObservers} method
+ * causes all of its observers to be notified of the change by a call
+ * to their {@code update} method.
+ * <p>
+ * The order in which notifications will be delivered is unspecified.
+ * The default implementation provided in the Observable class will
+ * notify Observers in the order in which they registered interest, but
+ * subclasses may change this order, use no guaranteed order, deliver
+ * notifications on separate threads, or may guarantee that their
+ * subclass follows this order, as they choose.
+ * <p>
+ * Note that this notification mechanism has nothing to do with threads
+ * and is completely separate from the {@code wait} and {@code notify}
+ * mechanism of class {@code Object}.
+ * <p>
+ * When an observable object is newly created, its set of observers is
+ * empty. Two observers are considered the same if and only if the
+ * {@code equals} method returns true for them.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable#notifyObservers()
+ * @see     java.util.Observable#notifyObservers(java.lang.Object)
+ * @see     java.util.Observer
+ * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+ * @since   1.0
+ *
+ * @deprecated
+ * This class and the {@link Observer} interface have been deprecated.
+ * The event model supported by {@code Observer} and {@code Observable}
+ * is quite limited, the order of notifications delivered by
+ * {@code Observable} is unspecified, and state changes are not in
+ * one-for-one correspondence with notifications.
+ * For a richer event model, consider using the
+ * {@link java.beans} package.  For reliable and ordered
+ * messaging among threads, consider using one of the concurrent data
+ * structures in the {@link java.util.concurrent} package.
+ * For reactive streams style programming, see the
+ * {@link java.util.concurrent.Flow} API.
+ */
+@Deprecated(since="9")
+public class Observable {
+    private boolean changed = false;
+    private Vector<Observer> obs;
+
+    /** Construct an Observable with zero Observers. */
+
+    public Observable() {
+        obs = new Vector<>();
+    }
+
+    /**
+     * Adds an observer to the set of observers for this object, provided
+     * that it is not the same as some observer already in the set.
+     * The order in which notifications will be delivered to multiple
+     * observers is not specified. See the class comment.
+     *
+     * @param   o   an observer to be added.
+     * @throws NullPointerException   if the parameter o is null.
+     */
+    public synchronized void addObserver(Observer o) {
+        if (o == null)
+            throw new NullPointerException();
+        if (!obs.contains(o)) {
+            obs.addElement(o);
+        }
+    }
+
+    /**
+     * Deletes an observer from the set of observers of this object.
+     * Passing {@code null} to this method will have no effect.
+     * @param   o   the observer to be deleted.
+     */
+    public synchronized void deleteObserver(Observer o) {
+        obs.removeElement(o);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * {@code hasChanged} method, then notify all of its observers
+     * and then call the {@code clearChanged} method to
+     * indicate that this object has no longer changed.
+     * <p>
+     * Each observer has its {@code update} method called with two
+     * arguments: this observable object and {@code null}. In other
+     * words, this method is equivalent to:
+     * <blockquote>{@code
+     * notifyObservers(null)}</blockquote>
+     *
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers() {
+        notifyObservers(null);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * {@code hasChanged} method, then notify all of its observers
+     * and then call the {@code clearChanged} method to indicate
+     * that this object has no longer changed.
+     * <p>
+     * Each observer has its {@code update} method called with two
+     * arguments: this observable object and the {@code arg} argument.
+     *
+     * @param   arg   any object.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers(Object arg) {
+        /*
+         * a temporary array buffer, used as a snapshot of the state of
+         * current Observers.
+         */
+        Object[] arrLocal;
+
+        synchronized (this) {
+            /* We don't want the Observer doing callbacks into
+             * arbitrary code while holding its own Monitor.
+             * The code where we extract each Observable from
+             * the Vector and store the state of the Observer
+             * needs synchronization, but notifying observers
+             * does not (should not).  The worst result of any
+             * potential race-condition here is that:
+             * 1) a newly-added Observer will miss a
+             *   notification in progress
+             * 2) a recently unregistered Observer will be
+             *   wrongly notified when it doesn't care
+             */
+            // Android-changed: Call out to hasChanged() to figure out if something changes.
+            // Upstream code avoids calling the nonfinal hasChanged() from the synchronized block,
+            // but that would break compatibility for apps that override that method.
+            // if (!changed)
+            if (!hasChanged())
+                return;
+            arrLocal = obs.toArray();
+            clearChanged();
+        }
+
+        for (int i = arrLocal.length-1; i>=0; i--)
+            ((Observer)arrLocal[i]).update(this, arg);
+    }
+
+    /**
+     * Clears the observer list so that this object no longer has any observers.
+     */
+    public synchronized void deleteObservers() {
+        obs.removeAllElements();
+    }
+
+    /**
+     * Marks this {@code Observable} object as having been changed; the
+     * {@code hasChanged} method will now return {@code true}.
+     */
+    protected synchronized void setChanged() {
+        changed = true;
+    }
+
+    /**
+     * Indicates that this object has no longer changed, or that it has
+     * already notified all of its observers of its most recent change,
+     * so that the {@code hasChanged} method will now return {@code false}.
+     * This method is called automatically by the
+     * {@code notifyObservers} methods.
+     *
+     * @see     java.util.Observable#notifyObservers()
+     * @see     java.util.Observable#notifyObservers(java.lang.Object)
+     */
+    protected synchronized void clearChanged() {
+        changed = false;
+    }
+
+    /**
+     * Tests if this object has changed.
+     *
+     * @return  {@code true} if and only if the {@code setChanged}
+     *          method has been called more recently than the
+     *          {@code clearChanged} method on this object;
+     *          {@code false} otherwise.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#setChanged()
+     */
+    public synchronized boolean hasChanged() {
+        return changed;
+    }
+
+    /**
+     * Returns the number of observers of this {@code Observable} object.
+     *
+     * @return  the number of observers of this object.
+     */
+    public synchronized int countObservers() {
+        return obs.size();
+    }
+}
diff --git a/android-35/java/util/Observer.java b/android-35/java/util/Observer.java
new file mode 100644
index 0000000..47f7933
--- /dev/null
+++ b/android-35/java/util/Observer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * A class can implement the {@code Observer} interface when it
+ * wants to be informed of changes in observable objects.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable
+ * @since   1.0
+ *
+ * @deprecated
+ * This interface has been deprecated. See the {@link Observable}
+ * class for further information.
+ */
+@Deprecated(since="9")
+public interface Observer {
+    /**
+     * This method is called whenever the observed object is changed. An
+     * application calls an {@code Observable} object's
+     * {@code notifyObservers} method to have all the object's
+     * observers notified of the change.
+     *
+     * @param   o     the observable object.
+     * @param   arg   an argument passed to the {@code notifyObservers}
+     *                 method.
+     */
+    void update(Observable o, Object arg);
+}
diff --git a/android-35/java/util/Optional.java b/android-35/java/util/Optional.java
new file mode 100644
index 0000000..d9f54c9
--- /dev/null
+++ b/android-35/java/util/Optional.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * A container object which may or may not contain a non-{@code null} value.
+ * If a value is present, {@code isPresent()} returns {@code true}. If no
+ * value is present, the object is considered <i>empty</i> and
+ * {@code isPresent()} returns {@code false}.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(Object) orElse()}
+ * (returns a default value if no value is present) and
+ * {@link #ifPresent(Consumer) ifPresent()} (performs an
+ * action if a value is present).
+ *
+ * <p>This is a <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
+ *
+ * @apiNote
+ * {@code Optional} is primarily intended for use as a method return type where
+ * there is a clear need to represent "no result," and where using {@code null}
+ * is likely to cause errors. A variable whose type is {@code Optional} should
+ * never itself be {@code null}; it should always point to an {@code Optional}
+ * instance.
+ *
+ * @param <T> the type of value
+ * @since 1.8
+ */
[email protected]
+public final class Optional<T> {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final Optional<?> EMPTY = new Optional<>(null);
+
+    /**
+     * If non-null, the value; if null, indicates no value is present
+     */
+    private final T value;
+
+    /**
+     * Returns an empty {@code Optional} instance.  No value is present for this
+     * {@code Optional}.
+     *
+     * @apiNote
+     * Though it may be tempting to do so, avoid testing if an object is empty
+     * by comparing with {@code ==} or {@code !=} against instances returned by
+     * {@code Optional.empty()}.  There is no guarantee that it is a singleton.
+     * Instead, use {@link #isEmpty()} or {@link #isPresent()}.
+     *
+     * @param <T> The type of the non-existent value
+     * @return an empty {@code Optional}
+     */
+    public static<T> Optional<T> empty() {
+        @SuppressWarnings("unchecked")
+        Optional<T> t = (Optional<T>) EMPTY;
+        return t;
+    }
+
+    /**
+     * Constructs an instance with the described value.
+     *
+     * @param value the value to describe; it's the caller's responsibility to
+     *        ensure the value is non-{@code null} unless creating the singleton
+     *        instance returned by {@code empty()}.
+     */
+    private Optional(T value) {
+        this.value = value;
+    }
+
+    /**
+     * Returns an {@code Optional} describing the given non-{@code null}
+     * value.
+     *
+     * @param value the value to describe, which must be non-{@code null}
+     * @param <T> the type of the value
+     * @return an {@code Optional} with the value present
+     * @throws NullPointerException if value is {@code null}
+     */
+    public static <T> Optional<T> of(T value) {
+        return new Optional<>(Objects.requireNonNull(value));
+    }
+
+    /**
+     * Returns an {@code Optional} describing the given value, if
+     * non-{@code null}, otherwise returns an empty {@code Optional}.
+     *
+     * @param value the possibly-{@code null} value to describe
+     * @param <T> the type of the value
+     * @return an {@code Optional} with a present value if the specified value
+     *         is non-{@code null}, otherwise an empty {@code Optional}
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Optional<T> ofNullable(T value) {
+        return value == null ? (Optional<T>) EMPTY
+                             : new Optional<>(value);
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @apiNote
+     * The preferred alternative to this method is {@link #orElseThrow()}.
+     *
+     * @return the non-{@code null} value described by this {@code Optional}
+     * @throws NoSuchElementException if no value is present
+     */
+    public T get() {
+        if (value == null) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns {@code true}, otherwise {@code false}.
+     *
+     * @return {@code true} if a value is present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return value != null;
+    }
+
+    /**
+     * If a value is  not present, returns {@code true}, otherwise
+     * {@code false}.
+     *
+     * @return  {@code true} if a value is not present, otherwise {@code false}
+     * @since   11
+     */
+    public boolean isEmpty() {
+        return value == null;
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise does nothing.
+     *
+     * @param action the action to be performed, if a value is present
+     * @throws NullPointerException if value is present and the given action is
+     *         {@code null}
+     */
+    public void ifPresent(Consumer<? super T> action) {
+        if (value != null) {
+            action.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise performs the given empty-based action.
+     *
+     * @param action the action to be performed, if a value is present
+     * @param emptyAction the empty-based action to be performed, if no value is
+     *        present
+     * @throws NullPointerException if a value is present and the given action
+     *         is {@code null}, or no value is present and the given empty-based
+     *         action is {@code null}.
+     * @since 9
+     */
+    public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
+        if (value != null) {
+            action.accept(value);
+        } else {
+            emptyAction.run();
+        }
+    }
+
+    /**
+     * If a value is present, and the value matches the given predicate,
+     * returns an {@code Optional} describing the value, otherwise returns an
+     * empty {@code Optional}.
+     *
+     * @param predicate the predicate to apply to a value, if present
+     * @return an {@code Optional} describing the value of this
+     *         {@code Optional}, if a value is present and the value matches the
+     *         given predicate, otherwise an empty {@code Optional}
+     * @throws NullPointerException if the predicate is {@code null}
+     */
+    public Optional<T> filter(Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        if (!isPresent()) {
+            return this;
+        } else {
+            return predicate.test(value) ? this : empty();
+        }
+    }
+
+    /**
+     * If a value is present, returns an {@code Optional} describing (as if by
+     * {@link #ofNullable}) the result of applying the given mapping function to
+     * the value, otherwise returns an empty {@code Optional}.
+     *
+     * <p>If the mapping function returns a {@code null} result then this method
+     * returns an empty {@code Optional}.
+     *
+     * @apiNote
+     * This method supports post-processing on {@code Optional} values, without
+     * the need to explicitly check for a return status.  For example, the
+     * following code traverses a stream of URIs, selects one that has not
+     * yet been processed, and creates a path from that URI, returning
+     * an {@code Optional<Path>}:
+     *
+     * <pre>{@code
+     *     Optional<Path> p =
+     *         uris.stream().filter(uri -> !isProcessedYet(uri))
+     *                       .findFirst()
+     *                       .map(Paths::get);
+     * }</pre>
+     *
+     * Here, {@code findFirst} returns an {@code Optional<URI>}, and then
+     * {@code map} returns an {@code Optional<Path>} for the desired
+     * URI if one exists.
+     *
+     * @param mapper the mapping function to apply to a value, if present
+     * @param <U> The type of the value returned from the mapping function
+     * @return an {@code Optional} describing the result of applying a mapping
+     *         function to the value of this {@code Optional}, if a value is
+     *         present, otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is {@code null}
+     */
+    public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent()) {
+            return empty();
+        } else {
+            return Optional.ofNullable(mapper.apply(value));
+        }
+    }
+
+    /**
+     * If a value is present, returns the result of applying the given
+     * {@code Optional}-bearing mapping function to the value, otherwise returns
+     * an empty {@code Optional}.
+     *
+     * <p>This method is similar to {@link #map(Function)}, but the mapping
+     * function is one whose result is already an {@code Optional}, and if
+     * invoked, {@code flatMap} does not wrap it within an additional
+     * {@code Optional}.
+     *
+     * @param <U> The type of value of the {@code Optional} returned by the
+     *            mapping function
+     * @param mapper the mapping function to apply to a value, if present
+     * @return the result of applying an {@code Optional}-bearing mapping
+     *         function to the value of this {@code Optional}, if a value is
+     *         present, otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is {@code null} or
+     *         returns a {@code null} result
+     */
+    public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent()) {
+            return empty();
+        } else {
+            @SuppressWarnings("unchecked")
+            Optional<U> r = (Optional<U>) mapper.apply(value);
+            return Objects.requireNonNull(r);
+        }
+    }
+
+    /**
+     * If a value is present, returns an {@code Optional} describing the value,
+     * otherwise returns an {@code Optional} produced by the supplying function.
+     *
+     * @param supplier the supplying function that produces an {@code Optional}
+     *        to be returned
+     * @return returns an {@code Optional} describing the value of this
+     *         {@code Optional}, if a value is present, otherwise an
+     *         {@code Optional} produced by the supplying function.
+     * @throws NullPointerException if the supplying function is {@code null} or
+     *         produces a {@code null} result
+     * @since 9
+     */
+    public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
+        Objects.requireNonNull(supplier);
+        if (isPresent()) {
+            return this;
+        } else {
+            @SuppressWarnings("unchecked")
+            Optional<T> r = (Optional<T>) supplier.get();
+            return Objects.requireNonNull(r);
+        }
+    }
+
+    /**
+     * If a value is present, returns a sequential {@link Stream} containing
+     * only that value, otherwise returns an empty {@code Stream}.
+     *
+     * @apiNote
+     * This method can be used to transform a {@code Stream} of optional
+     * elements to a {@code Stream} of present value elements:
+     * <pre>{@code
+     *     Stream<Optional<T>> os = ..
+     *     Stream<T> s = os.flatMap(Optional::stream)
+     * }</pre>
+     *
+     * @return the optional value as a {@code Stream}
+     * @since 9
+     */
+    public Stream<T> stream() {
+        if (!isPresent()) {
+            return Stream.empty();
+        } else {
+            return Stream.of(value);
+        }
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns
+     * {@code other}.
+     *
+     * @param other the value to be returned, if no value is present.
+     *        May be {@code null}.
+     * @return the value, if present, otherwise {@code other}
+     */
+    public T orElse(T other) {
+        return value != null ? value : other;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns the result
+     * produced by the supplying function.
+     *
+     * @param supplier the supplying function that produces a value to be returned
+     * @return the value, if present, otherwise the result produced by the
+     *         supplying function
+     * @throws NullPointerException if no value is present and the supplying
+     *         function is {@code null}
+     */
+    public T orElseGet(Supplier<? extends T> supplier) {
+        return value != null ? value : supplier.get();
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @return the non-{@code null} value described by this {@code Optional}
+     * @throws NoSuchElementException if no value is present
+     * @since 10
+     */
+    public T orElseThrow() {
+        if (value == null) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws an exception
+     * produced by the exception supplying function.
+     *
+     * @apiNote
+     * A method reference to the exception constructor with an empty argument
+     * list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier the supplying function that produces an
+     *        exception to be thrown
+     * @return the value, if present
+     * @throws X if no value is present
+     * @throws NullPointerException if no value is present and the exception
+     *          supplying function is {@code null}
+     */
+    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (value != null) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this {@code Optional}.
+     * The other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code Optional} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code equals()}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {@code true} if the other object is "equal to" this object
+     *         otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof Optional)) {
+            return false;
+        }
+
+        Optional<?> other = (Optional<?>) obj;
+        return Objects.equals(value, other.value);
+    }
+
+    /**
+     * Returns the hash code of the value, if present, otherwise {@code 0}
+     * (zero) if no value is present.
+     *
+     * @return hash code value of the present value or {@code 0} if no value is
+     *         present
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(value);
+    }
+
+    /**
+     * Returns a non-empty string representation of this {@code Optional}
+     * suitable for debugging.  The exact presentation format is unspecified and
+     * may vary between implementations and versions.
+     *
+     * @implSpec
+     * If a value is present the result must include its string representation
+     * in the result.  Empty and present {@code Optional}s must be unambiguously
+     * differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return value != null
+            ? ("Optional[" + value + "]")
+            : "Optional.empty";
+    }
+}
diff --git a/android-35/java/util/OptionalDouble.java b/android-35/java/util/OptionalDouble.java
new file mode 100644
index 0000000..bb40eaa
--- /dev/null
+++ b/android-35/java/util/OptionalDouble.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+
+/**
+ * A container object which may or may not contain a {@code double} value.
+ * If a value is present, {@code isPresent()} returns {@code true}. If no
+ * value is present, the object is considered <i>empty</i> and
+ * {@code isPresent()} returns {@code false}.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(double) orElse()}
+ * (returns a default value if no value is present) and
+ * {@link #ifPresent(DoubleConsumer) ifPresent()} (performs
+ * an action if a value is present).
+ *
+ * <p>This is a <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
+ *
+ * @apiNote
+ * {@code OptionalDouble} is primarily intended for use as a method return type where
+ * there is a clear need to represent "no result." A variable whose type is
+ * {@code OptionalDouble} should never itself be {@code null}; it should always point
+ * to an {@code OptionalDouble} instance.
+ *
+ * @since 1.8
+ */
[email protected]
+public final class OptionalDouble {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalDouble EMPTY = new OptionalDouble();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final double value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalDouble#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalDouble() {
+        this.isPresent = false;
+        this.value = Double.NaN;
+    }
+
+    /**
+     * Returns an empty {@code OptionalDouble} instance.  No value is present
+     * for this {@code OptionalDouble}.
+     *
+     * @apiNote
+     * Though it may be tempting to do so, avoid testing if an object is empty
+     * by comparing with {@code ==} or {@code !=} against instances returned by
+     * {@code OptionalDouble.empty()}.  There is no guarantee that it is a singleton.
+     * Instead, use {@link #isEmpty()} or {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalDouble}.
+     */
+    public static OptionalDouble empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the described value.
+     *
+     * @param value the double value to describe.
+     */
+    private OptionalDouble(double value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Returns an {@code OptionalDouble} describing the given value.
+     *
+     * @param value the value to describe
+     * @return an {@code OptionalDouble} with the value present
+     */
+    public static OptionalDouble of(double value) {
+        return new OptionalDouble(value);
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @apiNote
+     * The preferred alternative to this method is {@link #orElseThrow()}.
+     *
+     * @return the value described by this {@code OptionalDouble}
+     * @throws NoSuchElementException if no value is present
+     */
+    public double getAsDouble() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns {@code true}, otherwise {@code false}.
+     *
+     * @return {@code true} if a value is present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * If a value is not present, returns {@code true}, otherwise
+     * {@code false}.
+     *
+     * @return  {@code true} if a value is not present, otherwise {@code false}
+     * @since   11
+     */
+    public boolean isEmpty() {
+        return !isPresent;
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise does nothing.
+     *
+     * @param action the action to be performed, if a value is present
+     * @throws NullPointerException if value is present and the given action is
+     *         {@code null}
+     */
+    public void ifPresent(DoubleConsumer action) {
+        if (isPresent) {
+            action.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise performs the given empty-based action.
+     *
+     * @param action the action to be performed, if a value is present
+     * @param emptyAction the empty-based action to be performed, if no value is
+     * present
+     * @throws NullPointerException if a value is present and the given action
+     *         is {@code null}, or no value is present and the given empty-based
+     *         action is {@code null}.
+     * @since 9
+     */
+    public void ifPresentOrElse(DoubleConsumer action, Runnable emptyAction) {
+        if (isPresent) {
+            action.accept(value);
+        } else {
+            emptyAction.run();
+        }
+    }
+
+    /**
+     * If a value is present, returns a sequential {@link DoubleStream}
+     * containing only that value, otherwise returns an empty
+     * {@code DoubleStream}.
+     *
+     * @apiNote
+     * This method can be used to transform a {@code Stream} of optional doubles
+     * to a {@code DoubleStream} of present doubles:
+     * <pre>{@code
+     *     Stream<OptionalDouble> os = ..
+     *     DoubleStream s = os.flatMapToDouble(OptionalDouble::stream)
+     * }</pre>
+     *
+     * @return the optional value as a {@code DoubleStream}
+     * @since 9
+     */
+    public DoubleStream stream() {
+        if (isPresent) {
+            return DoubleStream.of(value);
+        } else {
+            return DoubleStream.empty();
+        }
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns
+     * {@code other}.
+     *
+     * @param other the value to be returned, if no value is present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public double orElse(double other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns the result
+     * produced by the supplying function.
+     *
+     * @param supplier the supplying function that produces a value to be returned
+     * @return the value, if present, otherwise the result produced by the
+     *         supplying function
+     * @throws NullPointerException if no value is present and the supplying
+     *         function is {@code null}
+     */
+    public double orElseGet(DoubleSupplier supplier) {
+        return isPresent ? value : supplier.getAsDouble();
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @return the value described by this {@code OptionalDouble}
+     * @throws NoSuchElementException if no value is present
+     * @since 10
+     */
+    public double orElseThrow() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws an exception
+     * produced by the exception supplying function.
+     *
+     * @apiNote
+     * A method reference to the exception constructor with an empty argument
+     * list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier the supplying function that produces an
+     *        exception to be thrown
+     * @return the value, if present
+     * @throws X if no value is present
+     * @throws NullPointerException if no value is present and the exception
+     *         supplying function is {@code null}
+     */
+    public<X extends Throwable> double orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this
+     * {@code OptionalDouble}. The other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalDouble} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via
+     * {@code Double.compare() == 0}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {@code true} if the other object is "equal to" this object
+     *         otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        return obj instanceof OptionalDouble other
+                && (isPresent && other.isPresent
+                ? Double.compare(value, other.value) == 0
+                : isPresent == other.isPresent);
+    }
+
+    /**
+     * Returns the hash code of the value, if present, otherwise {@code 0}
+     * (zero) if no value is present.
+     *
+     * @return hash code value of the present value or {@code 0} if no value is
+     *         present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Double.hashCode(value) : 0;
+    }
+
+    /**
+     * Returns a non-empty string representation of this {@code OptionalDouble}
+     * suitable for debugging.  The exact presentation format is unspecified and
+     * may vary between implementations and versions.
+     *
+     * @implSpec
+     * If a value is present the result must include its string representation
+     * in the result.  Empty and present {@code OptionalDouble}s must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? ("OptionalDouble[" + value + "]")
+                : "OptionalDouble.empty";
+    }
+}
diff --git a/android-35/java/util/OptionalInt.java b/android-35/java/util/OptionalInt.java
new file mode 100644
index 0000000..b22cb4d
--- /dev/null
+++ b/android-35/java/util/OptionalInt.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+import java.util.stream.IntStream;
+
+/**
+ * A container object which may or may not contain an {@code int} value.
+ * If a value is present, {@code isPresent()} returns {@code true}. If no
+ * value is present, the object is considered <i>empty</i> and
+ * {@code isPresent()} returns {@code false}.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(int) orElse()}
+ * (returns a default value if no value is present) and
+ * {@link #ifPresent(IntConsumer) ifPresent()} (performs an
+ * action if a value is present).
+ *
+ * <p>This is a <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
+ *
+ * @apiNote
+ * {@code OptionalInt} is primarily intended for use as a method return type where
+ * there is a clear need to represent "no result." A variable whose type is
+ * {@code OptionalInt} should never itself be {@code null}; it should always point
+ * to an {@code OptionalInt} instance.
+ *
+ * @since 1.8
+ */
[email protected]
+public final class OptionalInt {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalInt EMPTY = new OptionalInt();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final int value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote Generally only one empty instance, {@link OptionalInt#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalInt() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalInt} instance.  No value is present for
+     * this {@code OptionalInt}.
+     *
+     * @apiNote
+     * Though it may be tempting to do so, avoid testing if an object is empty
+     * by comparing with {@code ==} or {@code !=} against instances returned by
+     * {@code OptionalInt.empty()}.  There is no guarantee that it is a singleton.
+     * Instead, use {@link #isEmpty()} or {@link #isPresent()}.
+     *
+     * @return an empty {@code OptionalInt}
+     */
+    public static OptionalInt empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the described value.
+     *
+     * @param value the int value to describe
+     */
+    private OptionalInt(int value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Returns an {@code OptionalInt} describing the given value.
+     *
+     * @param value the value to describe
+     * @return an {@code OptionalInt} with the value present
+     */
+    public static OptionalInt of(int value) {
+        return new OptionalInt(value);
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @apiNote
+     * The preferred alternative to this method is {@link #orElseThrow()}.
+     *
+     * @return the value described by this {@code OptionalInt}
+     * @throws NoSuchElementException if no value is present
+     */
+    public int getAsInt() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns {@code true}, otherwise {@code false}.
+     *
+     * @return {@code true} if a value is present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * If a value is not present, returns {@code true}, otherwise
+     * {@code false}.
+     *
+     * @return  {@code true} if a value is not present, otherwise {@code false}
+     * @since   11
+     */
+    public boolean isEmpty() {
+        return !isPresent;
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise does nothing.
+     *
+     * @param action the action to be performed, if a value is present
+     * @throws NullPointerException if value is present and the given action is
+     *         {@code null}
+     */
+    public void ifPresent(IntConsumer action) {
+        if (isPresent) {
+            action.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise performs the given empty-based action.
+     *
+     * @param action the action to be performed, if a value is present
+     * @param emptyAction the empty-based action to be performed, if no value is
+     *        present
+     * @throws NullPointerException if a value is present and the given action
+     *         is {@code null}, or no value is present and the given empty-based
+     *         action is {@code null}.
+     * @since 9
+     */
+    public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) {
+        if (isPresent) {
+            action.accept(value);
+        } else {
+            emptyAction.run();
+        }
+    }
+
+    /**
+     * If a value is present, returns a sequential {@link IntStream} containing
+     * only that value, otherwise returns an empty {@code IntStream}.
+     *
+     * @apiNote
+     * This method can be used to transform a {@code Stream} of optional
+     * integers to an {@code IntStream} of present integers:
+     * <pre>{@code
+     *     Stream<OptionalInt> os = ..
+     *     IntStream s = os.flatMapToInt(OptionalInt::stream)
+     * }</pre>
+     *
+     * @return the optional value as an {@code IntStream}
+     * @since 9
+     */
+    public IntStream stream() {
+        if (isPresent) {
+            return IntStream.of(value);
+        } else {
+            return IntStream.empty();
+        }
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns
+     * {@code other}.
+     *
+     * @param other the value to be returned, if no value is present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public int orElse(int other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns the result
+     * produced by the supplying function.
+     *
+     * @param supplier the supplying function that produces a value to be returned
+     * @return the value, if present, otherwise the result produced by the
+     *         supplying function
+     * @throws NullPointerException if no value is present and the supplying
+     *         function is {@code null}
+     */
+    public int orElseGet(IntSupplier supplier) {
+        return isPresent ? value : supplier.getAsInt();
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @return the value described by this {@code OptionalInt}
+     * @throws NoSuchElementException if no value is present
+     * @since 10
+     */
+    public int orElseThrow() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws an exception
+     * produced by the exception supplying function.
+     *
+     * @apiNote
+     * A method reference to the exception constructor with an empty argument
+     * list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier the supplying function that produces an
+     *        exception to be thrown
+     * @return the value, if present
+     * @throws X if no value is present
+     * @throws NullPointerException if no value is present and the exception
+     *         supplying function is {@code null}
+     */
+    public<X extends Throwable> int orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this
+     * {@code OptionalInt}.  The other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalInt} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {@code true} if the other object is "equal to" this object
+     *         otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        return obj instanceof OptionalInt other
+                && (isPresent && other.isPresent
+                ? value == other.value
+                : isPresent == other.isPresent);
+    }
+
+    /**
+     * Returns the hash code of the value, if present, otherwise {@code 0}
+     * (zero) if no value is present.
+     *
+     * @return hash code value of the present value or {@code 0} if no value is
+     *         present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Integer.hashCode(value) : 0;
+    }
+
+    /**
+     * Returns a non-empty string representation of this {@code OptionalInt}
+     * suitable for debugging.  The exact presentation format is unspecified and
+     * may vary between implementations and versions.
+     *
+     * @implSpec
+     * If a value is present the result must include its string representation
+     * in the result.  Empty and present {@code OptionalInt}s must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? ("OptionalInt[" + value + "]")
+                : "OptionalInt.empty";
+    }
+}
diff --git a/android-35/java/util/OptionalLong.java b/android-35/java/util/OptionalLong.java
new file mode 100644
index 0000000..0657453
--- /dev/null
+++ b/android-35/java/util/OptionalLong.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+import java.util.stream.LongStream;
+
+/**
+ * A container object which may or may not contain a {@code long} value.
+ * If a value is present, {@code isPresent()} returns {@code true}. If no
+ * value is present, the object is considered <i>empty</i> and
+ * {@code isPresent()} returns {@code false}.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(long) orElse()}
+ * (returns a default value if no value is present) and
+ * {@link #ifPresent(LongConsumer) ifPresent()} (performs an
+ * action if a value is present).
+ *
+ * <p>This is a <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
+ *
+ * @apiNote
+ * {@code OptionalLong} is primarily intended for use as a method return type where
+ * there is a clear need to represent "no result." A variable whose type is
+ * {@code OptionalLong} should never itself be {@code null}; it should always point
+ * to an {@code OptionalLong} instance.
+ *
+ * @since 1.8
+ */
[email protected]
+public final class OptionalLong {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalLong EMPTY = new OptionalLong();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final long value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalLong#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalLong() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalLong} instance.  No value is present for
+     * this {@code OptionalLong}.
+     *
+     * @apiNote
+     * Though it may be tempting to do so, avoid testing if an object is empty
+     * by comparing with {@code ==} or {@code !=} against instances returned by
+     * {@code OptionalLong.empty()}.  There is no guarantee that it is a singleton.
+     * Instead, use {@link #isEmpty()} or {@link #isPresent()}.
+     *
+     * @return an empty {@code OptionalLong}.
+     */
+    public static OptionalLong empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the described value.
+     *
+     * @param value the long value to describe
+     */
+    private OptionalLong(long value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Returns an {@code OptionalLong} describing the given value.
+     *
+     * @param value the value to describe
+     * @return an {@code OptionalLong} with the value present
+     */
+    public static OptionalLong of(long value) {
+        return new OptionalLong(value);
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @apiNote
+     * The preferred alternative to this method is {@link #orElseThrow()}.
+     *
+     * @return the value described by this {@code OptionalLong}
+     * @throws NoSuchElementException if no value is present
+     */
+    public long getAsLong() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns {@code true}, otherwise {@code false}.
+     *
+     * @return {@code true} if a value is present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * If a value is not present, returns {@code true}, otherwise
+     * {@code false}.
+     *
+     * @return  {@code true} if a value is not present, otherwise {@code false}
+     * @since   11
+     */
+    public boolean isEmpty() {
+        return !isPresent;
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise does nothing.
+     *
+     * @param action the action to be performed, if a value is present
+     * @throws NullPointerException if value is present and the given action is
+     *         {@code null}
+     */
+    public void ifPresent(LongConsumer action) {
+        if (isPresent) {
+            action.accept(value);
+        }
+    }
+
+    /**
+     * If a value is present, performs the given action with the value,
+     * otherwise performs the given empty-based action.
+     *
+     * @param action the action to be performed, if a value is present
+     * @param emptyAction the empty-based action to be performed, if no value is
+     *        present
+     * @throws NullPointerException if a value is present and the given action
+     *         is {@code null}, or no value is present and the given empty-based
+     *         action is {@code null}.
+     * @since 9
+     */
+    public void ifPresentOrElse(LongConsumer action, Runnable emptyAction) {
+        if (isPresent) {
+            action.accept(value);
+        } else {
+            emptyAction.run();
+        }
+    }
+
+    /**
+     * If a value is present, returns a sequential {@link LongStream} containing
+     * only that value, otherwise returns an empty {@code LongStream}.
+     *
+     * @apiNote
+     * This method can be used to transform a {@code Stream} of optional longs
+     * to an {@code LongStream} of present longs:
+     * <pre>{@code
+     *     Stream<OptionalLong> os = ..
+     *     LongStream s = os.flatMapToLong(OptionalLong::stream)
+     * }</pre>
+     *
+     * @return the optional value as an {@code LongStream}
+     * @since 9
+     */
+    public LongStream stream() {
+        if (isPresent) {
+            return LongStream.of(value);
+        } else {
+            return LongStream.empty();
+        }
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns
+     * {@code other}.
+     *
+     * @param other the value to be returned, if no value is present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public long orElse(long other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise returns the result
+     * produced by the supplying function.
+     *
+     * @param supplier the supplying function that produces a value to be returned
+     * @return the value, if present, otherwise the result produced by the
+     *         supplying function
+     * @throws NullPointerException if no value is present and the supplying
+     *         function is {@code null}
+     */
+    public long orElseGet(LongSupplier supplier) {
+        return isPresent ? value : supplier.getAsLong();
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws
+     * {@code NoSuchElementException}.
+     *
+     * @return the value described by this {@code OptionalLong}
+     * @throws NoSuchElementException if no value is present
+     * @since 10
+     */
+    public long orElseThrow() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * If a value is present, returns the value, otherwise throws an exception
+     * produced by the exception supplying function.
+     *
+     * @apiNote
+     * A method reference to the exception constructor with an empty argument
+     * list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier the supplying function that produces an
+     *        exception to be thrown
+     * @return the value, if present
+     * @throws X if no value is present
+     * @throws NullPointerException if no value is present and the exception
+     *         supplying function is {@code null}
+     */
+    public<X extends Throwable> long orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this
+     * {@code OptionalLong}.  The other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalLong} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {@code true} if the other object is "equal to" this object
+     *         otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        return obj instanceof OptionalLong other
+                && (isPresent && other.isPresent
+                ? value == other.value
+                : isPresent == other.isPresent);
+    }
+
+    /**
+     * Returns the hash code of the value, if present, otherwise {@code 0}
+     * (zero) if no value is present.
+     *
+     * @return hash code value of the present value or {@code 0} if no value is
+     *         present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Long.hashCode(value) : 0;
+    }
+
+    /**
+     * Returns a non-empty string representation of this {@code OptionalLong}
+     * suitable for debugging.  The exact presentation format is unspecified and
+     * may vary between implementations and versions.
+     *
+     * @implSpec
+     * If a value is present the result must include its string representation
+     * in the result.  Empty and present {@code OptionalLong}s must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? ("OptionalLong[" + value + "]")
+                : "OptionalLong.empty";
+    }
+}
diff --git a/android-35/java/util/PrimitiveIterator.java b/android-35/java/util/PrimitiveIterator.java
new file mode 100644
index 0000000..e6fd3a5
--- /dev/null
+++ b/android-35/java/util/PrimitiveIterator.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A base type for primitive specializations of {@code Iterator}.  Specialized
+ * subtypes are provided for {@link OfInt int}, {@link OfLong long}, and
+ * {@link OfDouble double} values.
+ *
+ * <p>The specialized subtype default implementations of {@link Iterator#next}
+ * and {@link Iterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may offset any advantages gained when using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example, {@link PrimitiveIterator.OfInt#nextInt()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to {@link PrimitiveIterator.OfInt#next()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ *
+ * <p>Iteration of primitive values using boxing-based methods
+ * {@link Iterator#next next()} and
+ * {@link Iterator#forEachRemaining(java.util.function.Consumer) forEachRemaining()},
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @implNote
+ * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this PrimitiveIterator.  The
+ *        type must be a wrapper type for a primitive type, such as
+ *        {@code Integer} for the primitive {@code int} type.
+ * @param <T_CONS> the type of primitive consumer.  The type must be a
+ *        primitive specialization of {@link java.util.function.Consumer} for
+ *        {@code T}, such as {@link java.util.function.IntConsumer} for
+ *        {@code Integer}.
+ *
+ * @since 1.8
+ */
+public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
+
+    /**
+     * Performs the given action for each remaining element until all elements
+     * have been processed or the action throws an exception.  Actions are
+     * performed in the order of iteration, if that order is specified.
+     * Exceptions thrown by the action are relayed to the caller.
+     * <p>
+     * The behavior of an iterator is unspecified if the action modifies the
+     * source of elements in any way (even by calling the {@link #remove remove}
+     * method or other mutator methods of {@code Iterator} subtypes),
+     * unless an overriding class has specified a concurrent modification policy.
+     * <p>
+     * Subsequent behavior of an iterator is unspecified if the action throws an
+     * exception.
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     */
+    @SuppressWarnings("overloads")
+    void forEachRemaining(T_CONS action);
+
+    /**
+     * An Iterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public static interface OfInt extends PrimitiveIterator<Integer, IntConsumer> {
+
+        /**
+         * Returns the next {@code int} element in the iteration.
+         *
+         * @return the next {@code int} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        int nextInt();
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextInt());
+         * }</pre>
+         */
+        default void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextInt());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextInt()}, and returns that boxed result.
+         */
+        @Override
+        default Integer next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+            return nextInt();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code IntConsumer}, by boxing the argument of {@code IntConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.forEachRemainingInt(action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+
+    }
+
+    /**
+     * An Iterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public static interface OfLong extends PrimitiveIterator<Long, LongConsumer> {
+
+        /**
+         * Returns the next {@code long} element in the iteration.
+         *
+         * @return the next {@code long} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        long nextLong();
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextLong());
+         * }</pre>
+         */
+        default void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextLong());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextLong()}, and returns that boxed result.
+         */
+        @Override
+        default Long next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.nextLong()");
+            return nextLong();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code LongConsumer}, by boxing the argument of {@code LongConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.forEachRemainingLong(action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * An Iterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public static interface OfDouble extends PrimitiveIterator<Double, DoubleConsumer> {
+
+        /**
+         * Returns the next {@code double} element in the iteration.
+         *
+         * @return the next {@code double} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        double nextDouble();
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextDouble());
+         * }</pre>
+         */
+        default void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextDouble());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextDouble()}, and returns that boxed result.
+         */
+        @Override
+        default Double next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.nextLong()");
+            return nextDouble();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining}; otherwise the action is adapted to
+         * an instance of {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.forEachRemainingDouble(action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/PriorityQueue.java b/android-35/java/util/PriorityQueue.java
new file mode 100644
index 0000000..c1db1db
--- /dev/null
+++ b/android-35/java/util/PriorityQueue.java
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * An unbounded priority {@linkplain Queue queue} based on a priority heap.
+ * The elements of the priority queue are ordered according to their
+ * {@linkplain Comparable natural ordering}, or by a {@link Comparator}
+ * provided at queue construction time, depending on which constructor is
+ * used.  A priority queue does not permit {@code null} elements.
+ * A priority queue relying on natural ordering also does not permit
+ * insertion of non-comparable objects (doing so may result in
+ * {@code ClassCastException}).
+ *
+ * <p>The <em>head</em> of this queue is the <em>least</em> element
+ * with respect to the specified ordering.  If multiple elements are
+ * tied for least value, the head is one of those elements -- ties are
+ * broken arbitrarily.  The queue retrieval operations {@code poll},
+ * {@code remove}, {@code peek}, and {@code element} access the
+ * element at the head of the queue.
+ *
+ * <p>A priority queue is unbounded, but has an internal
+ * <i>capacity</i> governing the size of an array used to store the
+ * elements on the queue.  It is always at least as large as the queue
+ * size.  As elements are added to a priority queue, its capacity
+ * grows automatically.  The details of the growth policy are not
+ * specified.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} and the Spliterator provided in method {@link #spliterator()}
+ * are <em>not</em> guaranteed to traverse the elements of
+ * the priority queue in any particular order. If you need ordered
+ * traversal, consider using {@code Arrays.sort(pq.toArray())}.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * Multiple threads should not access a {@code PriorityQueue}
+ * instance concurrently if any of the threads modifies the queue.
+ * Instead, use the thread-safe {@link
+ * java.util.concurrent.PriorityBlockingQueue} class.
+ *
+ * <p>Implementation note: this implementation provides
+ * O(log(n)) time for the enqueuing and dequeuing methods
+ * ({@code offer}, {@code poll}, {@code remove()} and {@code add});
+ * linear time for the {@code remove(Object)} and {@code contains(Object)}
+ * methods; and constant time for the retrieval methods
+ * ({@code peek}, {@code element}, and {@code size}).
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Josh Bloch, Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+@SuppressWarnings("unchecked")
+public class PriorityQueue<E> extends AbstractQueue<E>
+    implements java.io.Serializable {
+
+    @java.io.Serial
+    private static final long serialVersionUID = -7720805057305804111L;
+
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    transient Object[] queue; // non-private to simplify nested class access
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    private final Comparator<? super E> comparator;
+
+    /**
+     * The number of times this priority queue has been
+     * <i>structurally modified</i>.  See AbstractList for gory details.
+     */
+    transient int modCount;     // non-private to simplify nested class access
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial
+     * capacity (11) that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     */
+    public PriorityQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial
+     * capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial capacity and
+     * whose elements are ordered according to the specified comparator.
+     *
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @since 1.8
+     */
+    public PriorityQueue(Comparator<? super E> comparator) {
+        this(DEFAULT_INITIAL_CAPACITY, comparator);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial capacity
+     * that orders its elements according to the specified comparator.
+     *
+     * @param  initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is
+     *         less than 1
+     */
+    public PriorityQueue(int initialCapacity,
+                         Comparator<? super E> comparator) {
+        // Note: This restriction of at least one is not actually needed,
+        // but continues for 1.5 compatibility
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.queue = new Object[initialCapacity];
+        this.comparator = comparator;
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified collection.  If the specified collection is an instance of
+     * a {@link SortedSet} or is another {@code PriorityQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public PriorityQueue(Collection<? extends E> c) {
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            initElementsFromCollection(ss);
+        }
+        else if (c instanceof PriorityQueue<?>) {
+            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            initFromPriorityQueue(pq);
+        }
+        else {
+            this.comparator = null;
+            initFromCollection(c);
+        }
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified priority queue.  This priority queue will be
+     * ordered according to the same ordering as the given priority
+     * queue.
+     *
+     * @param  c the priority queue whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of {@code c} cannot be
+     *         compared to one another according to {@code c}'s
+     *         ordering
+     * @throws NullPointerException if the specified priority queue or any
+     *         of its elements are null
+     */
+    public PriorityQueue(PriorityQueue<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initFromPriorityQueue(c);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified sorted set.   This priority queue will be ordered
+     * according to the same ordering as the given sorted set.
+     *
+     * @param  c the sorted set whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified sorted
+     *         set cannot be compared to one another according to the
+     *         sorted set's ordering
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    public PriorityQueue(SortedSet<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initElementsFromCollection(c);
+    }
+
+    /** Ensures that queue[0] exists, helping peek() and poll(). */
+    private static Object[] ensureNonEmpty(Object[] es) {
+        return (es.length > 0) ? es : new Object[1];
+    }
+
+    private void initFromPriorityQueue(PriorityQueue<? extends E> c) {
+        if (c.getClass() == PriorityQueue.class) {
+            this.queue = ensureNonEmpty(c.toArray());
+            this.size = c.size();
+        } else {
+            initFromCollection(c);
+        }
+    }
+
+    private void initElementsFromCollection(Collection<? extends E> c) {
+        Object[] es = c.toArray();
+        int len = es.length;
+        if (c.getClass() != ArrayList.class)
+            es = Arrays.copyOf(es, len, Object[].class);
+        if (len == 1 || this.comparator != null)
+            for (Object e : es)
+                if (e == null)
+                    throw new NullPointerException();
+        this.queue = ensureNonEmpty(es);
+        this.size = len;
+    }
+
+    /**
+     * Initializes queue array with elements from the given Collection.
+     *
+     * @param c the collection
+     */
+    private void initFromCollection(Collection<? extends E> c) {
+        initElementsFromCollection(c);
+        heapify();
+    }
+
+    /**
+     * Increases the capacity of the array.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        int oldCapacity = queue.length;
+        // Double size if small; else grow by 50%
+        int newCapacity = ArraysSupport.newLength(oldCapacity,
+                minCapacity - oldCapacity, /* minimum growth */
+                oldCapacity < 64 ? oldCapacity + 2 : oldCapacity >> 1
+                                           /* preferred growth */);
+        queue = Arrays.copyOf(queue, newCapacity);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        modCount++;
+        int i = size;
+        if (i >= queue.length)
+            grow(i + 1);
+        if (i == 0) {
+            // Android-changed: Keep old behavior on Android 13 or below. http://b/289878283
+            boolean usePreAndroidUBehavior = VMRuntime.getSdkVersion() < VersionCodes.UPSIDE_DOWN_CAKE
+                || !Compatibility.isChangeEnabled(PRIORITY_QUEUE_OFFER_NON_COMPARABLE_ONE_ELEMENT);
+            if (usePreAndroidUBehavior) {
+                queue[0] = e;
+            } else {
+                siftUp(i, e);
+            }
+        } else {
+            siftUp(i, e);
+        }
+        size = i + 1;
+        return true;
+    }
+
+    public E peek() {
+        return (E) queue[0];
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                if (o.equals(es[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * 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 and only 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) {
+        int i = indexOf(o);
+        if (i == -1)
+            return false;
+        else {
+            removeAt(i);
+            return true;
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     *
+     * @param o element to be removed from this queue, if present
+     */
+    void removeEq(Object o) {
+        final Object[] es = queue;
+        for (int i = 0, n = size; i < n; i++) {
+            if (o == es[i]) {
+                removeAt(i);
+                break;
+            }
+        }
+    }
+
+    /**
+     * 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) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(queue, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If the queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than the queue), the element in
+     * the array immediately following the end of the collection is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final int size = this.size;
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(queue, size, a.getClass());
+        System.arraycopy(queue, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The iterator
+     * does not return the elements in any particular order.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private final class Itr implements Iterator<E> {
+        /**
+         * Index (into queue array) of element to be returned by
+         * subsequent call to next.
+         */
+        private int cursor;
+
+        /**
+         * Index of element returned by most recent call to next,
+         * unless that element came from the forgetMeNot list.
+         * Set to -1 if element is deleted by a call to remove.
+         */
+        private int lastRet = -1;
+
+        /**
+         * A queue of elements that were moved from the unvisited portion of
+         * the heap into the visited portion as a result of "unlucky" element
+         * removals during the iteration.  (Unlucky element removals are those
+         * that require a siftup instead of a siftdown.)  We must visit all of
+         * the elements in this list to complete the iteration.  We do this
+         * after we've completed the "normal" iteration.
+         *
+         * We expect that most iterations, even those involving removals,
+         * will not need to store elements in this field.
+         */
+        private ArrayDeque<E> forgetMeNot;
+
+        /**
+         * Element returned by the most recent call to next iff that
+         * element was drawn from the forgetMeNot list.
+         */
+        private E lastRetElt;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Queue should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        private int expectedModCount = modCount;
+
+        Itr() {}                        // prevent access constructor creation
+
+        public boolean hasNext() {
+            return cursor < size ||
+                (forgetMeNot != null && !forgetMeNot.isEmpty());
+        }
+
+        public E next() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (cursor < size)
+                return (E) queue[lastRet = cursor++];
+            if (forgetMeNot != null) {
+                lastRet = -1;
+                lastRetElt = forgetMeNot.poll();
+                if (lastRetElt != null)
+                    return lastRetElt;
+            }
+            throw new NoSuchElementException();
+        }
+
+        public void remove() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (lastRet != -1) {
+                E moved = PriorityQueue.this.removeAt(lastRet);
+                lastRet = -1;
+                if (moved == null)
+                    cursor--;
+                else {
+                    if (forgetMeNot == null)
+                        forgetMeNot = new ArrayDeque<>();
+                    forgetMeNot.add(moved);
+                }
+            } else if (lastRetElt != null) {
+                PriorityQueue.this.removeEq(lastRetElt);
+                lastRetElt = null;
+            } else {
+                throw new IllegalStateException();
+            }
+            expectedModCount = modCount;
+        }
+    }
+
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Removes all of the elements from this priority queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        final Object[] es = queue;
+        for (int i = 0, n = size; i < n; i++)
+            es[i] = null;
+        size = 0;
+    }
+
+    public E poll() {
+        final Object[] es;
+        final E result;
+
+        if ((result = (E) ((es = queue)[0])) != null) {
+            modCount++;
+            final int n;
+            final E x = (E) es[(n = --size)];
+            es[n] = null;
+            if (n > 0) {
+                final Comparator<? super E> cmp;
+                if ((cmp = comparator) == null)
+                    siftDownComparable(0, x, es, n);
+                else
+                    siftDownUsingComparator(0, x, es, n, cmp);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     *
+     * Normally this method leaves the elements at up to i-1,
+     * inclusive, untouched.  Under these circumstances, it returns
+     * null.  Occasionally, in order to maintain the heap invariant,
+     * it must swap a later element of the list with one earlier than
+     * i.  Under these circumstances, this method returns the element
+     * that was previously at the end of the list and is now at some
+     * position before i. This fact is used by iterator.remove so as to
+     * avoid missing traversing elements.
+     */
+    E removeAt(int i) {
+        // assert i >= 0 && i < size;
+        final Object[] es = queue;
+        modCount++;
+        int s = --size;
+        if (s == i) // removed last element
+            es[i] = null;
+        else {
+            E moved = (E) es[s];
+            es[s] = null;
+            siftDown(i, moved);
+            if (es[i] == moved) {
+                siftUp(i, moved);
+                if (es[i] != moved)
+                    return moved;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons, the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftUp(int k, E x) {
+        if (comparator != null)
+            siftUpUsingComparator(k, x, queue, comparator);
+        else
+            siftUpComparable(k, x, queue);
+    }
+
+    private static <T> void siftUpComparable(int k, T x, Object[] es) {
+        Comparable<? super T> key = (Comparable<? super T>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = es[parent];
+            if (key.compareTo((T) e) >= 0)
+                break;
+            es[k] = e;
+            k = parent;
+        }
+        es[k] = key;
+    }
+
+    private static <T> void siftUpUsingComparator(
+        int k, T x, Object[] es, Comparator<? super T> cmp) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = es[parent];
+            if (cmp.compare(x, (T) e) >= 0)
+                break;
+            es[k] = e;
+            k = parent;
+        }
+        es[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftDown(int k, E x) {
+        if (comparator != null)
+            siftDownUsingComparator(k, x, queue, size, comparator);
+        else
+            siftDownComparable(k, x, queue, size);
+    }
+
+    private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
+        // assert n > 0;
+        Comparable<? super T> key = (Comparable<? super T>)x;
+        int half = n >>> 1;           // loop while a non-leaf
+        while (k < half) {
+            int child = (k << 1) + 1; // assume left child is least
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n &&
+                ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
+                c = es[child = right];
+            if (key.compareTo((T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
+        }
+        es[k] = key;
+    }
+
+    private static <T> void siftDownUsingComparator(
+        int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
+        // assert n > 0;
+        int half = n >>> 1;
+        while (k < half) {
+            int child = (k << 1) + 1;
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
+                c = es[child = right];
+            if (cmp.compare(x, (T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
+        }
+        es[k] = x;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     * This classic algorithm due to Floyd (1964) is known to be O(size).
+     */
+    private void heapify() {
+        final Object[] es = queue;
+        int n = size, i = (n >>> 1) - 1;
+        final Comparator<? super E> cmp;
+        if ((cmp = comparator) == null)
+            for (; i >= 0; i--)
+                siftDownComparable(i, (E) es[i], es, n);
+        else
+            for (; i >= 0; i--)
+                siftDownUsingComparator(i, (E) es[i], es, n, cmp);
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this
+     * queue, or {@code null} if this queue is sorted according to
+     * the {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @return the comparator used to order this queue, or
+     *         {@code null} if this queue is sorted according to the
+     *         natural ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The length of the array backing the instance is
+     *             emitted (int), followed by all of its elements
+     *             (each an {@code Object}) in the proper order.
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out element count, and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out array length, for compatibility with 1.5 version
+        s.writeInt(Math.max(2, size + 1));
+
+        // Write out all elements in the "proper order".
+        final Object[] es = queue;
+        for (int i = 0, n = size; i < n; i++)
+            s.writeObject(es[i]);
+    }
+
+    /**
+     * Reconstitutes the {@code PriorityQueue} instance from a stream
+     * (that is, deserializes it).
+     *
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in (and discard) array length
+        s.readInt();
+
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
+        final Object[] es = queue = new Object[Math.max(size, 1)];
+
+        // Read in all elements.
+        for (int i = 0, n = size; i < n; i++)
+            es[i] = s.readObject();
+
+        // Elements are guaranteed to be in "proper order", but the
+        // spec has never explained what that might be.
+        heapify();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * queue. The spliterator does not traverse elements in any particular order
+     * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported).
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public final Spliterator<E> spliterator() {
+        return new PriorityQueueSpliterator(0, -1, 0);
+    }
+
+    final class PriorityQueueSpliterator implements Spliterator<E> {
+        private int index;            // current index, modified on advance/split
+        private int fence;            // -1 until first use
+        private int expectedModCount; // initialized when fence set
+
+        /** Creates new spliterator covering the given range. */
+        PriorityQueueSpliterator(int origin, int fence, int expectedModCount) {
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                expectedModCount = modCount;
+                hi = fence = size;
+            }
+            return hi;
+        }
+
+        public PriorityQueueSpliterator trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PriorityQueueSpliterator(lo, index = mid, expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (fence < 0) { fence = size; expectedModCount = modCount; }
+            final Object[] es = queue;
+            int i, hi; E e;
+            for (i = index, index = hi = fence; i < hi; i++) {
+                if ((e = (E) es[i]) == null)
+                    break;      // must be CME
+                action.accept(e);
+            }
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (fence < 0) { fence = size; expectedModCount = modCount; }
+            int i;
+            if ((i = index) < fence) {
+                index = i + 1;
+                E e;
+                if ((e = (E) queue[i]) == null
+                    || modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() {
+            return getFence() - index;
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final int expectedModCount = ++modCount;
+        final Object[] es = queue;
+        final int end = size;
+        int i;
+        // Optimize for initial run of survivors
+        for (i = 0; i < end && !filter.test((E) es[i]); i++)
+            ;
+        if (i >= end) {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        final int beg = i;
+        final long[] deathRow = nBits(end - beg);
+        deathRow[0] = 1L;   // set bit 0
+        for (i = beg + 1; i < end; i++)
+            if (filter.test((E) es[i]))
+                setBit(deathRow, i - beg);
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+        int w = beg;
+        for (i = beg; i < end; i++)
+            if (isClear(deathRow, i - beg))
+                es[w++] = es[i];
+        for (i = size = w; i < end; i++)
+            es[i] = null;
+        heapify();
+        return true;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        final Object[] es = queue;
+        for (int i = 0, n = size; i < n; i++)
+            action.accept((E) es[i]);
+        if (expectedModCount != modCount)
+            throw new ConcurrentModificationException();
+    }
+
+    //  Android-added: Backward-compatible flag for offer() API.
+    /**
+     * Since Android 14, {@link PriorityQueue#offer(E)} requires all elements to be comparable if
+     * there was no comparator. Previously, the first element being added did not need to be
+     * comparable.
+     *
+     * This flag is enabled for apps targeting Android 14+.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.UPSIDE_DOWN_CAKE)
+    public static final long PRIORITY_QUEUE_OFFER_NON_COMPARABLE_ONE_ELEMENT = 289878283L;
+}
diff --git a/android-35/java/util/Properties.java b/android-35/java/util/Properties.java
new file mode 100644
index 0000000..a70a059
--- /dev/null
+++ b/android-35/java/util/Properties.java
@@ -0,0 +1,1582 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.OutputStreamWriter;
+import java.io.BufferedWriter;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.StreamCorruptedException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.util.ArraysSupport;
+
+// Android-removed: Dead native2ascii links.
+// These links are also gone in OpenJDK 9.
+/**
+ * The {@code Properties} class represents a persistent set of
+ * properties. The {@code Properties} can be saved to a stream
+ * or loaded from a stream. Each key and its corresponding value in
+ * the property list is a string.
+ * <p>
+ * A property list can contain another property list as its
+ * "defaults"; this second property list is searched if
+ * the property key is not found in the original property list.
+ * <p>
+ * Because {@code Properties} inherits from {@code Hashtable}, the
+ * {@code put} and {@code putAll} methods can be applied to a
+ * {@code Properties} object.  Their use is strongly discouraged as they
+ * allow the caller to insert entries whose keys or values are not
+ * {@code Strings}.  The {@code setProperty} method should be used
+ * instead.  If the {@code store} or {@code save} method is called
+ * on a "compromised" {@code Properties} object that contains a
+ * non-{@code String} key or value, the call will fail. Similarly,
+ * the call to the {@code propertyNames} or {@code list} method
+ * will fail if it is called on a "compromised" {@code Properties}
+ * object that contains a non-{@code String} key.
+ *
+ * <p>
+ * The iterators returned by the {@code iterator} method of this class's
+ * "collection views" (that is, {@code entrySet()}, {@code keySet()}, and
+ * {@code values()}) may not fail-fast (unlike the Hashtable implementation).
+ * These iterators are guaranteed to traverse elements as they existed upon
+ * construction exactly once, and may (but are not guaranteed to) reflect any
+ * modifications subsequent to construction.
+ * <p>
+ * The {@link #load(java.io.Reader) load(Reader)} {@code /}
+ * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
+ * methods load and store properties from and to a character based stream
+ * in a simple line-oriented format specified below.
+ *
+ * The {@link #load(java.io.InputStream) load(InputStream)} {@code /}
+ * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
+ * methods work the same way as the load(Reader)/store(Writer, String) pair, except
+ * the input/output stream is encoded in ISO 8859-1 character encoding.
+ * Characters that cannot be directly represented in this encoding can be written using
+ * Unicode escapes as defined in section {@jls 3.3} of
+ * <cite>The Java Language Specification</cite>;
+ * only a single 'u' character is allowed in an escape
+ * sequence.
+ *
+ * <p> The {@link #loadFromXML(InputStream)} and {@link
+ * #storeToXML(OutputStream, String, String)} methods load and store properties
+ * in a simple XML format.  By default the UTF-8 character encoding is used,
+ * however a specific encoding may be specified if required. Implementations
+ * are required to support UTF-8 and UTF-16 and may support other encodings.
+ * An XML properties document has the following DOCTYPE declaration:
+ *
+ * <pre>
+ * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+ * </pre>
+ * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
+ * <i>not</i> accessed when exporting or importing properties; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>
+ *    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
+ *
+ *    &lt;!-- DTD for properties --&gt;
+ *
+ *    &lt;!ELEMENT properties ( comment?, entry* ) &gt;
+ *
+ *    &lt;!ATTLIST properties version CDATA #FIXED "1.0"&gt;
+ *
+ *    &lt;!ELEMENT comment (#PCDATA) &gt;
+ *
+ *    &lt;!ELEMENT entry (#PCDATA) &gt;
+ *
+ *    &lt;!ATTLIST entry key CDATA #REQUIRED&gt;
+ * </pre>
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * {@code Properties} object without the need for external synchronization.
+ *
+ * @apiNote
+ * The {@code Properties} class does not inherit the concept of a load factor
+ * from its superclass, {@code Hashtable}.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Xueming Shen
+ * @since   1.0
+ */
+public class Properties extends Hashtable<Object,Object> {
+    /**
+     * use serialVersionUID from JDK 1.1.X for interoperability
+     */
+    @java.io.Serial
+    private static final long serialVersionUID = 4112578634029874840L;
+
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    /**
+     * A property list that contains default values for any keys not
+     * found in this property list.
+     *
+     * @serial
+     */
+    protected volatile Properties defaults;
+
+    /**
+     * Properties does not store values in its inherited Hashtable, but instead
+     * in an internal ConcurrentHashMap.  Synchronization is omitted from
+     * simple read operations.  Writes and bulk operations remain synchronized,
+     * as in Hashtable.
+     */
+    private transient volatile ConcurrentHashMap<Object, Object> map;
+
+    /**
+     * Creates an empty property list with no default values.
+     *
+     * @implNote The initial capacity of a {@code Properties} object created
+     * with this constructor is unspecified.
+     */
+    public Properties() {
+        this(null, 8);
+    }
+
+    /**
+     * Creates an empty property list with no default values, and with an
+     * initial size accommodating the specified number of elements without the
+     * need to dynamically resize.
+     *
+     * @param  initialCapacity the {@code Properties} will be sized to
+     *         accommodate this many elements
+     * @throws IllegalArgumentException if the initial capacity is less than
+     *         zero.
+     */
+    public Properties(int initialCapacity) {
+        this(null, initialCapacity);
+    }
+
+    /**
+     * Creates an empty property list with the specified defaults.
+     *
+     * @implNote The initial capacity of a {@code Properties} object created
+     * with this constructor is unspecified.
+     *
+     * @param   defaults   the defaults.
+     */
+    public Properties(Properties defaults) {
+        this(defaults, 8);
+    }
+
+    private Properties(Properties defaults, int initialCapacity) {
+        // use package-private constructor to
+        // initialize unused fields with dummy values
+        super((Void) null);
+        map = new ConcurrentHashMap<>(initialCapacity);
+        this.defaults = defaults;
+
+        // Ensure writes can't be reordered
+        UNSAFE.storeFence();
+    }
+
+    /**
+     * Calls the {@code Hashtable} method {@code put}. Provided for
+     * parallelism with the {@code getProperty} method. Enforces use of
+     * strings for property keys and values. The value returned is the
+     * result of the {@code Hashtable} call to {@code put}.
+     *
+     * @param key the key to be placed into this property list.
+     * @param value the value corresponding to {@code key}.
+     * @return     the previous value of the specified key in this property
+     *             list, or {@code null} if it did not have one.
+     * @see #getProperty
+     * @since    1.2
+     */
+    public synchronized Object setProperty(String key, String value) {
+        return put(key, value);
+    }
+
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * character stream in a simple line-oriented format.
+     * <p>
+     * Properties are processed in terms of lines. There are two
+     * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
+     * A natural line is defined as a line of
+     * characters that is terminated either by a set of line terminator
+     * characters ({@code \n} or {@code \r} or {@code \r\n})
+     * or by the end of the stream. A natural line may be either a blank line,
+     * a comment line, or hold all or some of a key-element pair. A logical
+     * line holds all the data of a key-element pair, which may be spread
+     * out across several adjacent natural lines by escaping
+     * the line terminator sequence with a backslash character
+     * {@code \}.  Note that a comment line cannot be extended
+     * in this manner; every natural line that is a comment must have
+     * its own comment indicator, as described below. Lines are read from
+     * input until the end of the stream is reached.
+     *
+     * <p>
+     * A natural line that contains only white space characters is
+     * considered blank and is ignored.  A comment line has an ASCII
+     * {@code '#'} or {@code '!'} as its first non-white
+     * space character; comment lines are also ignored and do not
+     * encode key-element information.  In addition to line
+     * terminators, this format considers the characters space
+     * ({@code ' '}, {@code '\u005Cu0020'}), tab
+     * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
+     * ({@code '\f'}, {@code '\u005Cu000C'}) to be white
+     * space.
+     *
+     * <p>
+     * If a logical line is spread across several natural lines, the
+     * backslash escaping the line terminator sequence, the line
+     * terminator sequence, and any white space at the start of the
+     * following line have no affect on the key or element values.
+     * The remainder of the discussion of key and element parsing
+     * (when loading) will assume all the characters constituting
+     * the key and element appear on a single natural line after
+     * line continuation characters have been removed.  Note that
+     * it is <i>not</i> sufficient to only examine the character
+     * preceding a line terminator sequence to decide if the line
+     * terminator is escaped; there must be an odd number of
+     * contiguous backslashes for the line terminator to be escaped.
+     * Since the input is processed from left to right, a
+     * non-zero even number of 2<i>n</i> contiguous backslashes
+     * before a line terminator (or elsewhere) encodes <i>n</i>
+     * backslashes after escape processing.
+     *
+     * <p>
+     * The key contains all of the characters in the line starting
+     * with the first non-white space character and up to, but not
+     * including, the first unescaped {@code '='},
+     * {@code ':'}, or white space character other than a line
+     * terminator. All of these key termination characters may be
+     * included in the key by escaping them with a preceding backslash
+     * character; for example,<p>
+     *
+     * {@code \:\=}<p>
+     *
+     * would be the two-character key {@code ":="}.  Line
+     * terminator characters can be included using {@code \r} and
+     * {@code \n} escape sequences.  Any white space after the
+     * key is skipped; if the first non-white space character after
+     * the key is {@code '='} or {@code ':'}, then it is
+     * ignored and any white space characters after it are also
+     * skipped.  All remaining characters on the line become part of
+     * the associated element string; if there are no remaining
+     * characters, the element is the empty string
+     * {@code ""}.  Once the raw character sequences
+     * constituting the key and element are identified, escape
+     * processing is performed as described above.
+     *
+     * <p>
+     * As an example, each of the following three lines specifies the key
+     * {@code "Truth"} and the associated element value
+     * {@code "Beauty"}:
+     * <pre>
+     * Truth = Beauty
+     *  Truth:Beauty
+     * Truth                    :Beauty
+     * </pre>
+     * As another example, the following three lines specify a single
+     * property:
+     * <pre>
+     * fruits                           apple, banana, pear, \
+     *                                  cantaloupe, watermelon, \
+     *                                  kiwi, mango
+     * </pre>
+     * The key is {@code "fruits"} and the associated element is:
+     * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
+     * Note that a space appears before each {@code \} so that a space
+     * will appear after each comma in the final result; the {@code \},
+     * line terminator, and leading white space on the continuation line are
+     * merely discarded and are <i>not</i> replaced by one or more other
+     * characters.
+     * <p>
+     * As a third example, the line:
+     * <pre>cheeses
+     * </pre>
+     * specifies that the key is {@code "cheeses"} and the associated
+     * element is the empty string {@code ""}.
+     * <p>
+     * <a id="unicodeescapes"></a>
+     * Characters in keys and elements can be represented in escape
+     * sequences similar to those used for character and string literals
+     * (see sections {@jls 3.3} and {@jls 3.10.6} of
+     * <cite>The Java Language Specification</cite>).
+     *
+     * The differences from the character escape sequences and Unicode
+     * escapes used for characters and strings are:
+     *
+     * <ul>
+     * <li> Octal escapes are not recognized.
+     *
+     * <li> The character sequence {@code \b} does <i>not</i>
+     * represent a backspace character.
+     *
+     * <li> The method does not treat a backslash character,
+     * {@code \}, before a non-valid escape character as an
+     * error; the backslash is silently dropped.  For example, in a
+     * Java string the sequence {@code "\z"} would cause a
+     * compile time error.  In contrast, this method silently drops
+     * the backslash.  Therefore, this method treats the two character
+     * sequence {@code "\b"} as equivalent to the single
+     * character {@code 'b'}.
+     *
+     * <li> Escapes are not necessary for single and double quotes;
+     * however, by the rule above, single and double quote characters
+     * preceded by a backslash still yield single and double quote
+     * characters, respectively.
+     *
+     * <li> Only a single 'u' character is allowed in a Unicode escape
+     * sequence.
+     *
+     * </ul>
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param   reader   the input character stream.
+     * @throws  IOException  if an error occurred when reading from the
+     *          input stream.
+     * @throws  IllegalArgumentException if a malformed Unicode escape
+     *          appears in the input.
+     * @throws  NullPointerException if {@code reader} is null.
+     * @since   1.6
+     */
+    public synchronized void load(Reader reader) throws IOException {
+        Objects.requireNonNull(reader, "reader parameter is null");
+        load0(new LineReader(reader));
+    }
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * byte stream. The input stream is in a simple line-oriented
+     * format as specified in
+     * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
+     * the ISO 8859-1 character encoding; that is each byte is one Latin1
+     * character. Characters not in Latin1, and certain special characters,
+     * are represented in keys and elements using Unicode escapes as defined in
+     * section {@jls 3.3} of
+     * <cite>The Java Language Specification</cite>.
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param      inStream   the input stream.
+     * @throws     IOException  if an error occurred when reading from the
+     *             input stream.
+     * @throws     IllegalArgumentException if the input stream contains a
+     *             malformed Unicode escape sequence.
+     * @throws     NullPointerException if {@code inStream} is null.
+     * @since 1.2
+     */
+    public synchronized void load(InputStream inStream) throws IOException {
+        Objects.requireNonNull(inStream, "inStream parameter is null");
+        load0(new LineReader(inStream));
+    }
+
+    private void load0(LineReader lr) throws IOException {
+        StringBuilder outBuffer = new StringBuilder();
+        int limit;
+        int keyLen;
+        int valueStart;
+        boolean hasSep;
+        boolean precedingBackslash;
+
+        while ((limit = lr.readLine()) >= 0) {
+            keyLen = 0;
+            valueStart = limit;
+            hasSep = false;
+
+            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
+            precedingBackslash = false;
+            while (keyLen < limit) {
+                char c = lr.lineBuf[keyLen];
+                //need check if escaped.
+                if ((c == '=' ||  c == ':') && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    hasSep = true;
+                    break;
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
+                } else if (Character.isWhitespace(c) && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    break;
+                }
+                if (c == '\\') {
+                    precedingBackslash = !precedingBackslash;
+                } else {
+                    precedingBackslash = false;
+                }
+                keyLen++;
+            }
+            while (valueStart < limit) {
+                char c = lr.lineBuf[valueStart];
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // if (c != ' ' && c != '\t' &&  c != '\f') {
+                if (!Character.isWhitespace(c)) {
+                    if (!hasSep && (c == '=' ||  c == ':')) {
+                        hasSep = true;
+                    } else {
+                        break;
+                    }
+                }
+                valueStart++;
+            }
+            String key = loadConvert(lr.lineBuf, 0, keyLen, outBuffer);
+            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, outBuffer);
+            put(key, value);
+        }
+    }
+
+    /* Read in a "logical line" from an InputStream/Reader, skip all comment
+     * and blank lines and filter out those leading whitespace characters
+     * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
+     * Method returns the char length of the "logical line" and stores
+     * the line in "lineBuf".
+     */
+    private static class LineReader {
+        LineReader(InputStream inStream) {
+            this.inStream = inStream;
+            inByteBuf = new byte[8192];
+        }
+
+        LineReader(Reader reader) {
+            this.reader = reader;
+            inCharBuf = new char[8192];
+        }
+
+        char[] lineBuf = new char[1024];
+        private byte[] inByteBuf;
+        private char[] inCharBuf;
+        private int inLimit = 0;
+        private int inOff = 0;
+        private InputStream inStream;
+        private Reader reader;
+
+        int readLine() throws IOException {
+            // use locals to optimize for interpreted performance
+            int len = 0;
+            int off = inOff;
+            int limit = inLimit;
+
+            boolean skipWhiteSpace = true;
+            boolean appendedLineBegin = false;
+            boolean precedingBackslash = false;
+            boolean fromStream = inStream != null;
+            byte[] byteBuf = inByteBuf;
+            char[] charBuf = inCharBuf;
+            char[] lineBuf = this.lineBuf;
+            char c;
+
+            while (true) {
+                if (off >= limit) {
+                    inLimit = limit = fromStream ? inStream.read(byteBuf)
+                                                 : reader.read(charBuf);
+                    if (limit <= 0) {
+                        if (len == 0) {
+                            return -1;
+                        }
+                        return precedingBackslash ? len - 1 : len;
+                    }
+                    off = 0;
+                }
+
+                // (char)(byte & 0xFF) is equivalent to calling a ISO8859-1 decoder.
+                c = (fromStream) ? (char)(byteBuf[off++] & 0xFF) : charBuf[off++];
+
+                if (skipWhiteSpace) {
+                    // Android-changed: Treat all whitespace the same. http://b/25998006
+                    // if (c == ' ' || c == '\t' || c == '\f') {
+                    if (Character.isWhitespace(c)) {
+                        continue;
+                    }
+                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
+                        continue;
+                    }
+                    skipWhiteSpace = false;
+                    appendedLineBegin = false;
+
+                }
+                if (len == 0) { // Still on a new logical line
+                    if (c == '#' || c == '!') {
+                        // Comment, quickly consume the rest of the line
+
+                        // When checking for new line characters a range check,
+                        // starting with the higher bound ('\r') means one less
+                        // branch in the common case.
+                        commentLoop: while (true) {
+                            if (fromStream) {
+                                byte b;
+                                while (off < limit) {
+                                    b = byteBuf[off++];
+                                    if (b <= '\r' && (b == '\r' || b == '\n'))
+                                        break commentLoop;
+                                }
+                                if (off == limit) {
+                                    inLimit = limit = inStream.read(byteBuf);
+                                    if (limit <= 0) { // EOF
+                                        return -1;
+                                    }
+                                    off = 0;
+                                }
+                            } else {
+                                while (off < limit) {
+                                    c = charBuf[off++];
+                                    if (c <= '\r' && (c == '\r' || c == '\n'))
+                                        break commentLoop;
+                                }
+                                if (off == limit) {
+                                    inLimit = limit = reader.read(charBuf);
+                                    if (limit <= 0) { // EOF
+                                        return -1;
+                                    }
+                                    off = 0;
+                                }
+                            }
+                        }
+                        skipWhiteSpace = true;
+                        continue;
+                    }
+                }
+
+                if (c != '\n' && c != '\r') {
+                    lineBuf[len++] = c;
+                    if (len == lineBuf.length) {
+                        lineBuf = new char[ArraysSupport.newLength(len, 1, len)];
+                        System.arraycopy(this.lineBuf, 0, lineBuf, 0, len);
+                        this.lineBuf = lineBuf;
+                    }
+                    // flip the preceding backslash flag
+                    precedingBackslash = (c == '\\') ? !precedingBackslash : false;
+                } else {
+                    // reached EOL
+                    if (len == 0) {
+                        skipWhiteSpace = true;
+                        continue;
+                    }
+                    if (off >= limit) {
+                        inLimit = limit = fromStream ? inStream.read(byteBuf)
+                                                     : reader.read(charBuf);
+                        off = 0;
+                        if (limit <= 0) { // EOF
+                            return precedingBackslash ? len - 1 : len;
+                        }
+                    }
+                    if (precedingBackslash) {
+                        // backslash at EOL is not part of the line
+                        len -= 1;
+                        // skip leading whitespace characters in the following line
+                        skipWhiteSpace = true;
+                        appendedLineBegin = true;
+                        precedingBackslash = false;
+                        // take care not to include any subsequent \n
+                        if (c == '\r') {
+                            if (fromStream) {
+                                if (byteBuf[off] == '\n') {
+                                    off++;
+                                }
+                            } else {
+                                if (charBuf[off] == '\n') {
+                                    off++;
+                                }
+                            }
+                        }
+                    } else {
+                        inOff = off;
+                        return len;
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Converts encoded &#92;uxxxx to unicode chars
+     * and changes special saved chars to their original forms
+     */
+    private String loadConvert(char[] in, int off, int len, StringBuilder out) {
+        char aChar;
+        int end = off + len;
+        int start = off;
+        while (off < end) {
+            aChar = in[off++];
+            if (aChar == '\\') {
+                break;
+            }
+        }
+        if (off == end) { // No backslash
+            return new String(in, start, len);
+        }
+
+        // backslash found at off - 1, reset the shared buffer, rewind offset
+        out.setLength(0);
+        off--;
+        out.append(in, start, off - start);
+
+        while (off < end) {
+            aChar = in[off++];
+            if (aChar == '\\') {
+                // No need to bounds check since LineReader::readLine excludes
+                // unescaped \s at the end of the line
+                aChar = in[off++];
+                if(aChar == 'u') {
+                    // Read the xxxx
+                    if (off > end - 4)
+                        throw new IllegalArgumentException(
+                                     "Malformed \\uxxxx encoding.");
+                    int value = 0;
+                    for (int i = 0; i < 4; i++) {
+                        aChar = in[off++];
+                        value = switch (aChar) {
+                            case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> (value << 4) + aChar - '0';
+                            case 'a', 'b', 'c', 'd', 'e', 'f'                     -> (value << 4) + 10 + aChar - 'a';
+                            case 'A', 'B', 'C', 'D', 'E', 'F'                     -> (value << 4) + 10 + aChar - 'A';
+                            default -> throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
+                        };
+                    }
+                    out.append((char)value);
+                } else {
+                    if (aChar == 't') aChar = '\t';
+                    else if (aChar == 'r') aChar = '\r';
+                    else if (aChar == 'n') aChar = '\n';
+                    else if (aChar == 'f') aChar = '\f';
+                    out.append(aChar);
+                }
+            } else {
+                out.append(aChar);
+            }
+        }
+        return out.toString();
+    }
+
+    /*
+     * Converts unicodes to encoded &#92;uxxxx and escapes
+     * special characters with a preceding slash
+     */
+    private String saveConvert(String theString,
+                               boolean escapeSpace,
+                               boolean escapeUnicode) {
+        int len = theString.length();
+        int bufLen = len * 2;
+        if (bufLen < 0) {
+            bufLen = Integer.MAX_VALUE;
+        }
+        StringBuilder outBuffer = new StringBuilder(bufLen);
+        HexFormat hex = HexFormat.of().withUpperCase();
+        for(int x=0; x<len; x++) {
+            char aChar = theString.charAt(x);
+            // Handle common case first, selecting largest block that
+            // avoids the specials below
+            if ((aChar > 61) && (aChar < 127)) {
+                if (aChar == '\\') {
+                    outBuffer.append('\\'); outBuffer.append('\\');
+                    continue;
+                }
+                outBuffer.append(aChar);
+                continue;
+            }
+            switch(aChar) {
+                case ' ':
+                    if (x == 0 || escapeSpace)
+                        outBuffer.append('\\');
+                    outBuffer.append(' ');
+                    break;
+                case '\t':outBuffer.append('\\'); outBuffer.append('t');
+                          break;
+                case '\n':outBuffer.append('\\'); outBuffer.append('n');
+                          break;
+                case '\r':outBuffer.append('\\'); outBuffer.append('r');
+                          break;
+                case '\f':outBuffer.append('\\'); outBuffer.append('f');
+                          break;
+                case '=': // Fall through
+                case ':': // Fall through
+                case '#': // Fall through
+                case '!':
+                    outBuffer.append('\\'); outBuffer.append(aChar);
+                    break;
+                default:
+                    if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
+                        outBuffer.append("\\u");
+                        outBuffer.append(hex.toHexDigits(aChar));
+                    } else {
+                        outBuffer.append(aChar);
+                    }
+            }
+        }
+        return outBuffer.toString();
+    }
+
+    private static void writeComments(BufferedWriter bw, String comments)
+        throws IOException {
+        HexFormat hex = HexFormat.of().withUpperCase();
+        bw.write("#");
+        int len = comments.length();
+        int current = 0;
+        int last = 0;
+        while (current < len) {
+            char c = comments.charAt(current);
+            if (c > '\u00ff' || c == '\n' || c == '\r') {
+                if (last != current)
+                    bw.write(comments.substring(last, current));
+                if (c > '\u00ff') {
+                    bw.write("\\u");
+                    bw.write(hex.toHexDigits(c));
+                } else {
+                    bw.newLine();
+                    if (c == '\r' &&
+                        current != len - 1 &&
+                        comments.charAt(current + 1) == '\n') {
+                        current++;
+                    }
+                    if (current == len - 1 ||
+                        (comments.charAt(current + 1) != '#' &&
+                        comments.charAt(current + 1) != '!'))
+                        bw.write("#");
+                }
+                last = current + 1;
+            }
+            current++;
+        }
+        if (last != current)
+            bw.write(comments.substring(last, current));
+        bw.newLine();
+    }
+
+    /**
+     * Calls the {@code store(OutputStream out, String comments)} method
+     * and suppresses IOExceptions that were thrown.
+     *
+     * @deprecated This method does not throw an IOException if an I/O error
+     * occurs while saving the property list.  The preferred way to save a
+     * properties list is via the {@code store(OutputStream out,
+     * String comments)} method or the
+     * {@code storeToXML(OutputStream os, String comment)} method.
+     *
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @throws     ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not
+     *             {@code Strings}.
+     */
+    @Deprecated
+    public void save(OutputStream out, String comments)  {
+        try {
+            store(out, comments);
+        } catch (IOException e) {
+        }
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output character stream in a
+     * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
+     * method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * If the comments argument is not null, then an ASCII {@code #}
+     * character, the comments string, and a line separator are first written
+     * to the output stream. Thus, the {@code comments} can serve as an
+     * identifying comment. Any one of a line feed ('\n'), a carriage
+     * return ('\r'), or a carriage return followed immediately by a line feed
+     * in comments is replaced by a line separator generated by the {@code Writer}
+     * and if the next character in comments is not character {@code #} or
+     * character {@code !} then an ASCII {@code #} is written out
+     * after that line separator.
+     * <p>
+     * Next, a comment line is always written, consisting of an ASCII
+     * {@code #} character, the current date and time (as if produced
+     * by the {@code toString} method of {@code Date} for the
+     * current time), and a line separator as generated by the {@code Writer}.
+     * <p>
+     * Then every entry in this {@code Properties} table is
+     * written out, one per line. For each entry the key string is
+     * written, then an ASCII {@code =}, then the associated
+     * element string. For the key, all space characters are
+     * written with a preceding {@code \} character.  For the
+     * element, leading space characters, but not embedded or trailing
+     * space characters, are written with a preceding {@code \}
+     * character. The key and element characters {@code #},
+     * {@code !}, {@code =}, and {@code :} are written
+     * with a preceding backslash to ensure that they are properly loaded.
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     *
+     * @param   writer      an output character stream writer.
+     * @param   comments   a description of the property list.
+     * @throws     IOException if writing this property list to the specified
+     *             output stream throws an {@code IOException}.
+     * @throws     ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @throws     NullPointerException  if {@code writer} is null.
+     * @since 1.6
+     */
+    public void store(Writer writer, String comments)
+        throws IOException
+    {
+        store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
+                                                 : new BufferedWriter(writer),
+               comments,
+               false);
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output stream in a format suitable
+     * for loading into a {@code Properties} table using the
+     * {@link #load(InputStream) load(InputStream)} method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * This method outputs the comments, properties keys and values in
+     * the same format as specified in
+     * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
+     * with the following differences:
+     * <ul>
+     * <li>The stream is written using the ISO 8859-1 character encoding.
+     *
+     * <li>Characters not in Latin-1 in the comments are written as
+     * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
+     * hexadecimal value <i>xxxx</i>.
+     *
+     * <li>Characters less than {@code \u005Cu0020} and characters greater
+     * than {@code \u005Cu007E} in property keys or values are written
+     * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
+     * value <i>xxxx</i>.
+     * </ul>
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     *
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @throws     IOException if writing this property list to the specified
+     *             output stream throws an {@code IOException}.
+     * @throws     ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @throws     NullPointerException  if {@code out} is null.
+     * @since 1.2
+     */
+    public void store(OutputStream out, String comments)
+        throws IOException
+    {
+        // Android-changed: use java.nio.charset.StandardCharsets.
+        // store0(new BufferedWriter(new OutputStreamWriter(out, ISO_8859_1.INSTANCE)),
+        store0(new BufferedWriter(new OutputStreamWriter(out, ISO_8859_1)),
+               comments,
+               true);
+    }
+
+    private void store0(BufferedWriter bw, String comments, boolean escUnicode)
+        throws IOException
+    {
+        if (comments != null) {
+            writeComments(bw, comments);
+        }
+        bw.write("#" + new Date().toString());
+        bw.newLine();
+        synchronized (this) {
+            for (Map.Entry<Object, Object> e : entrySet()) {
+                String key = (String)e.getKey();
+                String val = (String)e.getValue();
+                key = saveConvert(key, true, escUnicode);
+                /* No need to escape embedded and trailing spaces for value, hence
+                 * pass false to flag.
+                 */
+                val = saveConvert(val, false, escUnicode);
+                bw.write(key + "=" + val);
+                bw.newLine();
+            }
+        }
+        bw.flush();
+    }
+
+    /**
+     * Loads all of the properties represented by the XML document on the
+     * specified input stream into this properties table.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     * Furthermore, the document must satisfy the properties DTD described
+     * above.
+     *
+     * <p> An implementation is required to read XML documents that use the
+     * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
+     * support additional encodings.
+     *
+     * <p>The specified stream is closed after this method returns.
+     *
+     * @param in the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an {@code IOException}.
+     * @throws java.io.UnsupportedEncodingException if the document's encoding
+     *         declaration can be read and it specifies an encoding that is not
+     *         supported
+     * @throws InvalidPropertiesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws NullPointerException if {@code in} is null.
+     * @see    #storeToXML(OutputStream, String, String)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public synchronized void loadFromXML(InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        //
+        // Objects.requireNonNull(in);
+        // PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
+        // handler.load(this, in);
+        XMLUtils.load(this, Objects.requireNonNull(in));
+        in.close();
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table.
+     *
+     * <p> An invocation of this method of the form {@code props.storeToXML(os,
+     * comment)} behaves in exactly the same way as the invocation
+     * {@code props.storeToXML(os, comment, "UTF-8");}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @param comment a description of the property list, or {@code null}
+     *        if no comment is desired.
+     * @throws IOException if writing to the specified output stream
+     *         results in an {@code IOException}.
+     * @throws NullPointerException if {@code os} is null.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not
+     *         {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment)
+        throws IOException
+    {
+        // storeToXML(os, comment, UTF_8.INSTANCE);
+        storeToXML(os, comment, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table, using the specified encoding.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     *
+     * <p>If the specified comment is {@code null} then no comment
+     * will be stored in the document.
+     *
+     * <p> An implementation is required to support writing of XML documents
+     * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+     * implementation may support additional encodings.
+     *
+     * <p>The specified stream remains open after this method returns.
+     *
+     * <p>This method behaves the same as
+     * {@linkplain #storeToXML(OutputStream os, String comment, Charset charset)}
+     * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset}
+     * using the given encoding name.
+     *
+     * @param os        the output stream on which to emit the XML document.
+     * @param comment   a description of the property list, or {@code null}
+     *                  if no comment is desired.
+     * @param  encoding the name of a supported
+     *                  <a href="../lang/package-summary.html#charenc">
+     *                  character encoding</a>
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an {@code IOException}.
+     * @throws java.io.UnsupportedEncodingException if the encoding is not
+     *         supported by the implementation.
+     * @throws NullPointerException if {@code os} is {@code null},
+     *         or if {@code encoding} is {@code null}.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment, String encoding)
+        throws IOException {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        /*
+        Objects.requireNonNull(os);
+        Objects.requireNonNull(encoding);
+
+        try {
+            Charset charset = Charset.forName(encoding);
+            storeToXML(os, comment, charset);
+        } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+            throw new UnsupportedEncodingException(encoding);
+        }
+        */
+        XMLUtils.save(this, Objects.requireNonNull(os), comment,
+                       Objects.requireNonNull(encoding));
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table, using the specified encoding.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     *
+     * <p>If the specified comment is {@code null} then no comment
+     * will be stored in the document.
+     *
+     * <p> An implementation is required to support writing of XML documents
+     * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+     * implementation may support additional encodings.
+     *
+     * <p> Unmappable characters for the specified charset will be encoded as
+     * numeric character references.
+     *
+     * <p>The specified stream remains open after this method returns.
+     *
+     * @param os        the output stream on which to emit the XML document.
+     * @param comment   a description of the property list, or {@code null}
+     *                  if no comment is desired.
+     * @param charset   the charset
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an {@code IOException}.
+     * @throws NullPointerException if {@code os} or {@code charset} is {@code null}.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 10
+     */
+    public void storeToXML(OutputStream os, String comment, Charset charset)
+        throws IOException {
+        Objects.requireNonNull(os, "OutputStream");
+        Objects.requireNonNull(charset, "Charset");
+        // Objects.requireNonNull(os, "OutputStream");
+        // PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
+        // handler.store(this, os, comment, charset);
+        storeToXML(os, comment, charset.name());
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns
+     * {@code null} if the property is not found.
+     *
+     * @param   key   the property key.
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key) {
+        Object oval = map.get(key);
+        String sval = (oval instanceof String) ? (String)oval : null;
+        Properties defaults;
+        return ((sval == null) && ((defaults = this.defaults) != null)) ? defaults.getProperty(key) : sval;
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns the
+     * default value argument if the property is not found.
+     *
+     * @param   key            the hashtable key.
+     * @param   defaultValue   a default value.
+     *
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key, String defaultValue) {
+        String val = getProperty(key);
+        return (val == null) ? defaultValue : val;
+    }
+
+    /**
+     * Returns an enumeration of all the keys in this property list,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.
+     *
+     * @return  an enumeration of all the keys in this property list, including
+     *          the keys in the default property list.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @see     java.util.Enumeration
+     * @see     java.util.Properties#defaults
+     * @see     #stringPropertyNames
+     */
+    public Enumeration<?> propertyNames() {
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        return h.keys();
+    }
+
+    /**
+     * Returns an unmodifiable set of keys from this property list
+     * where the key and its corresponding value are strings,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.  Properties whose key or value is not
+     * of type {@code String} are omitted.
+     * <p>
+     * The returned set is not backed by this {@code Properties} object.
+     * Changes to this {@code Properties} object are not reflected in the
+     * returned set.
+     *
+     * @return  an unmodifiable set of keys in this property list where
+     *          the key and its corresponding value are strings,
+     *          including the keys in the default property list.
+     * @see     java.util.Properties#defaults
+     * @since   1.6
+     */
+    public Set<String> stringPropertyNames() {
+        Map<String, String> h = new HashMap<>();
+        enumerateStringProperties(h);
+        return Collections.unmodifiableSet(h.keySet());
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     */
+    public void list(PrintStream out) {
+        out.println("-- listing properties --");
+        Map<String, Object> h = new HashMap<>();
+        enumerate(h);
+        for (Map.Entry<String, Object> e : h.entrySet()) {
+            String key = e.getKey();
+            String val = (String)e.getValue();
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @since   1.1
+     */
+    /*
+     * Rather than use an anonymous inner class to share common code, this
+     * method is duplicated in order to ensure that a non-1.1 compiler can
+     * compile this file.
+     */
+    public void list(PrintWriter out) {
+        out.println("-- listing properties --");
+        Map<String, Object> h = new HashMap<>();
+        enumerate(h);
+        for (Map.Entry<String, Object> e : h.entrySet()) {
+            String key = e.getKey();
+            String val = (String)e.getValue();
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs into the specified Map.
+     * @param h the Map
+     * @throws ClassCastException if any of the property keys
+     *         is not of String type.
+     */
+    private void enumerate(Map<String, Object> h) {
+        if (defaults != null) {
+            defaults.enumerate(h);
+        }
+        for (Map.Entry<Object, Object> e : entrySet()) {
+            String key = (String)e.getKey();
+            h.put(key, e.getValue());
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs into the specified Map
+     * and omits the property if the key or value is not a string.
+     * @param h the Map
+     */
+    private void enumerateStringProperties(Map<String, String> h) {
+        if (defaults != null) {
+            defaults.enumerateStringProperties(h);
+        }
+        for (Map.Entry<Object, Object> e : entrySet()) {
+            Object k = e.getKey();
+            Object v = e.getValue();
+            if (k instanceof String && v instanceof String) {
+                h.put((String) k, (String) v);
+            }
+        }
+    }
+
+    //
+    // Hashtable methods overridden and delegated to a ConcurrentHashMap instance
+
+    @Override
+    public int size() {
+        return map.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    @Override
+    public Enumeration<Object> keys() {
+        // CHM.keys() returns Iterator w/ remove() - instead wrap keySet()
+        return Collections.enumeration(map.keySet());
+    }
+
+    @Override
+    public Enumeration<Object> elements() {
+        // CHM.elements() returns Iterator w/ remove() - instead wrap values()
+        return Collections.enumeration(map.values());
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        return map.contains(value);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return map.containsKey(key);
+    }
+
+    @Override
+    public Object get(Object key) {
+        return map.get(key);
+    }
+
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        return map.put(key, value);
+    }
+
+    @Override
+    public synchronized Object remove(Object key) {
+        return map.remove(key);
+    }
+
+    @Override
+    public synchronized void putAll(Map<?, ?> t) {
+        map.putAll(t);
+    }
+
+    @Override
+    public synchronized void clear() {
+        map.clear();
+    }
+
+    @Override
+    public synchronized String toString() {
+        return map.toString();
+    }
+
+    @Override
+    public Set<Object> keySet() {
+        return Collections.synchronizedSet(map.keySet(), this);
+    }
+
+    @Override
+    public Collection<Object> values() {
+        return Collections.synchronizedCollection(map.values(), this);
+    }
+
+    @Override
+    public Set<Map.Entry<Object, Object>> entrySet() {
+        return Collections.synchronizedSet(new EntrySet(map.entrySet()), this);
+    }
+
+    /*
+     * Properties.entrySet() should not support add/addAll, however
+     * ConcurrentHashMap.entrySet() provides add/addAll.  This class wraps the
+     * Set returned from CHM, changing add/addAll to throw UOE.
+     */
+    private static class EntrySet implements Set<Map.Entry<Object, Object>> {
+        private Set<Map.Entry<Object,Object>> entrySet;
+
+        private EntrySet(Set<Map.Entry<Object, Object>> entrySet) {
+            this.entrySet = entrySet;
+        }
+
+        @Override public int size() { return entrySet.size(); }
+        @Override public boolean isEmpty() { return entrySet.isEmpty(); }
+        @Override public boolean contains(Object o) { return entrySet.contains(o); }
+        @Override public Object[] toArray() { return entrySet.toArray(); }
+        @Override public <T> T[] toArray(T[] a) { return entrySet.toArray(a); }
+        @Override public void clear() { entrySet.clear(); }
+        @Override public boolean remove(Object o) { return entrySet.remove(o); }
+
+        @Override
+        public boolean add(Map.Entry<Object, Object> e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends Map.Entry<Object, Object>> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> c) {
+            return entrySet.containsAll(c);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return o == this || entrySet.equals(o);
+        }
+
+        @Override
+        public int hashCode() {
+            return entrySet.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return entrySet.toString();
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            return entrySet.removeAll(c);
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            return entrySet.retainAll(c);
+        }
+
+        @Override
+        public Iterator<Map.Entry<Object, Object>> iterator() {
+            return entrySet.iterator();
+        }
+    }
+
+    @Override
+    public synchronized boolean equals(Object o) {
+        return map.equals(o);
+    }
+
+    @Override
+    public synchronized int hashCode() {
+        return map.hashCode();
+    }
+
+    @Override
+    public Object getOrDefault(Object key, Object defaultValue) {
+        return map.getOrDefault(key, defaultValue);
+    }
+
+    @Override
+    public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
+        map.forEach(action);
+    }
+
+    @Override
+    public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
+        map.replaceAll(function);
+    }
+
+    @Override
+    public synchronized Object putIfAbsent(Object key, Object value) {
+        return map.putIfAbsent(key, value);
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        return map.remove(key, value);
+    }
+
+    @Override
+    public synchronized boolean replace(Object key, Object oldValue, Object newValue) {
+        return map.replace(key, oldValue, newValue);
+    }
+
+    @Override
+    public synchronized Object replace(Object key, Object value) {
+        return map.replace(key, value);
+    }
+
+    @Override
+    public synchronized Object computeIfAbsent(Object key,
+            Function<? super Object, ?> mappingFunction) {
+        return map.computeIfAbsent(key, mappingFunction);
+    }
+
+    @Override
+    public synchronized Object computeIfPresent(Object key,
+            BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return map.computeIfPresent(key, remappingFunction);
+    }
+
+    @Override
+    public synchronized Object compute(Object key,
+            BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return map.compute(key, remappingFunction);
+    }
+
+    @Override
+    public synchronized Object merge(Object key, Object value,
+            BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return map.merge(key, value, remappingFunction);
+    }
+
+    //
+    // Special Hashtable methods
+
+    @Override
+    protected void rehash() { /* no-op */ }
+
+    @Override
+    public synchronized Object clone() {
+        Properties clone = (Properties) cloneHashtable();
+        clone.map = new ConcurrentHashMap<>(map);
+        return clone;
+    }
+
+    //
+    // Hashtable serialization overrides
+    // (these should emit and consume Hashtable-compatible stream)
+
+    @Override
+    void writeHashtable(ObjectOutputStream s) throws IOException {
+        var map = this.map;
+        List<Object> entryStack = new ArrayList<>(map.size() * 2); // an estimate
+
+        for (Map.Entry<Object, Object> entry : map.entrySet()) {
+            entryStack.add(entry.getValue());
+            entryStack.add(entry.getKey());
+        }
+
+        // Write out the simulated threshold, loadfactor
+        float loadFactor = 0.75f;
+        int count = entryStack.size() / 2;
+        int length = (int)(count / loadFactor) + (count / 20) + 3;
+        if (length > count && (length & 1) == 0) {
+            length--;
+        }
+        synchronized (map) { // in case of multiple concurrent serializations
+            defaultWriteHashtable(s, length, loadFactor);
+        }
+
+        // Write out simulated length and real count of elements
+        s.writeInt(length);
+        s.writeInt(count);
+
+        // Write out the key/value objects from the stacked entries
+        for (int i = entryStack.size() - 1; i >= 0; i--) {
+            s.writeObject(entryStack.get(i));
+        }
+    }
+
+    @Override
+    void readHashtable(ObjectInputStream s) throws IOException,
+            ClassNotFoundException {
+        // Read in the threshold and loadfactor
+        s.defaultReadObject();
+
+        // Read the original length of the array and number of elements
+        int origlength = s.readInt();
+        int elements = s.readInt();
+
+        // Validate # of elements
+        if (elements < 0) {
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+        }
+
+        // Constructing the backing map will lazily create an array when the first element is
+        // added, so check it before construction. Note that CHM's constructor takes a size
+        // that is the number of elements to be stored -- not the table size -- so it must be
+        // inflated by the default load factor of 0.75, then inflated to the next power of two.
+        // (CHM uses the same power-of-two computation as HashMap, and HashMap.tableSizeFor is
+        // accessible here.) Check Map.Entry[].class since it's the nearest public type to
+        // what is actually created.
+        SharedSecrets.getJavaObjectInputStreamAccess()
+                     .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor((int)(elements / 0.75)));
+
+        // create CHM of appropriate capacity
+        var map = new ConcurrentHashMap<>(elements);
+
+        // Read all the key/value objects
+        for (; elements > 0; elements--) {
+            Object key = s.readObject();
+            Object value = s.readObject();
+            map.put(key, value);
+        }
+        this.map = map;
+    }
+}
diff --git a/android-35/java/util/PropertyPermission.java b/android-35/java/util/PropertyPermission.java
new file mode 100644
index 0000000..838c758
--- /dev/null
+++ b/android-35/java/util/PropertyPermission.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final class PropertyPermission extends BasicPermission {
+
+    public PropertyPermission(String name, String actions) { super("", ""); }
+}
diff --git a/android-35/java/util/PropertyResourceBundle.java b/android-35/java/util/PropertyResourceBundle.java
new file mode 100644
index 0000000..b729894
--- /dev/null
+++ b/android-35/java/util/PropertyResourceBundle.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ */
+
+package java.util;
+
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.IOException;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnmappableCharacterException;
+import sun.security.action.GetPropertyAction;
+import sun.util.PropertyResourceBundleCharset;
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * {@code PropertyResourceBundle} is a concrete subclass of
+ * {@code ResourceBundle} that manages resources for a locale
+ * using a set of static strings from a property file. See
+ * {@link ResourceBundle ResourceBundle} for more information about resource
+ * bundles.
+ *
+ * <p>
+ * Unlike other types of resource bundle, you don't subclass
+ * {@code PropertyResourceBundle}.  Instead, you supply properties
+ * files containing the resource data.  {@code ResourceBundle.getBundle}
+ * will automatically look for the appropriate properties file and create a
+ * {@code PropertyResourceBundle} that refers to it. See
+ * {@link ResourceBundle#getBundle(String, Locale, ClassLoader) ResourceBundle.getBundle}
+ * for a complete description of the search and instantiation strategy.
+ *
+ * <p>
+ * The following <a id="sample">example</a> shows a member of a resource
+ * bundle family with the base name "MyResources".
+ * The text defines the bundle "MyResources_de",
+ * the German member of the bundle family.
+ * This member is based on {@code PropertyResourceBundle}, and the text
+ * therefore is the content of the file "MyResources_de.properties"
+ * (a related <a href="ListResourceBundle.html#sample">example</a> shows
+ * how you can add bundles to this family that are implemented as subclasses
+ * of {@code ListResourceBundle}).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ * # MessageFormat pattern
+ * s1=Die Platte \"{1}\" enth&auml;lt {0}.
+ *
+ * # location of {0} in pattern
+ * s2=1
+ *
+ * # sample disk name
+ * s3=Meine Platte
+ *
+ * # first ChoiceFormat choice
+ * s4=keine Dateien
+ *
+ * # second ChoiceFormat choice
+ * s5=eine Datei
+ *
+ * # third ChoiceFormat choice
+ * s6={0,number} Dateien
+ *
+ * # sample date
+ * s7=3. M&auml;rz 1996
+ * </pre>
+ * </blockquote>
+ *
+ <!-- Android-removed: we're sticking to old behaviour for now.
+ * @apiNote
+ * {@code PropertyResourceBundle} can be constructed either
+ * from an {@code InputStream} or a {@code Reader}, which represents a property file.
+ * Constructing a {@code PropertyResourceBundle} instance from an {@code InputStream}
+ * requires that the input stream be encoded in {@code UTF-8}. By default, if a
+ * {@link java.nio.charset.MalformedInputException} or an
+ * {@link java.nio.charset.UnmappableCharacterException} occurs on reading the
+ * input stream, then the {@code PropertyResourceBundle} instance resets to the state
+ * before the exception, re-reads the input stream in {@code ISO-8859-1}, and
+ * continues reading. If the system property
+ * {@systemProperty java.util.PropertyResourceBundle.encoding} is set to either
+ * "ISO-8859-1" or "UTF-8", the input stream is solely read in that encoding,
+ * and throws the exception if it encounters an invalid sequence.
+ * If "ISO-8859-1" is specified, characters that cannot be represented in
+ * ISO-8859-1 encoding must be represented by Unicode Escapes as defined in section
+ * {@jls 3.3} of <cite>The Java Language Specification</cite>
+ * whereas the other constructor which takes a {@code Reader} does not have that limitation.
+ * Other encoding values are ignored for this system property.
+ * The system property is read and evaluated when initializing this class.
+ * Changing or removing the property has no effect after the initialization.
+ * --/>
+ * @implSpec
+ * The implementation of a {@code PropertyResourceBundle} subclass must be
+ * thread-safe if it's simultaneously used by multiple threads. The default
+ * implementations of the non-abstract methods in this class are thread-safe.
+ *
+ * @see ResourceBundle
+ * @see ListResourceBundle
+ * @see Properties
+ * @since 1.1
+ */
+public class PropertyResourceBundle extends ResourceBundle {
+
+    // Check whether the strict encoding is specified.
+    // The possible encoding is either "ISO-8859-1" or "UTF-8".
+    private static final String encoding = GetPropertyAction
+        .privilegedGetProperty("java.util.PropertyResourceBundle.encoding", "")
+        .toUpperCase(Locale.ROOT);
+
+    /**
+     * Creates a property resource bundle from an {@link java.io.InputStream
+     * InputStream}. This constructor reads the property file in UTF-8 by default.
+     * If a {@link java.nio.charset.MalformedInputException} or an
+     * {@link java.nio.charset.UnmappableCharacterException} occurs on reading the
+     * input stream, then the PropertyResourceBundle instance resets to the state
+     * before the exception, re-reads the input stream in {@code ISO-8859-1} and
+     * continues reading. If the system property
+     * {@code java.util.PropertyResourceBundle.encoding} is set to either
+     * "ISO-8859-1" or "UTF-8", the input stream is solely read in that encoding,
+     * and throws the exception if it encounters an invalid sequence. Other
+     * encoding values are ignored for this system property.
+     * The system property is read and evaluated when initializing this class.
+     * Changing or removing the property has no effect after the initialization.
+     *
+     * @param stream an InputStream that represents a property file
+     *        to read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code stream} is null
+     * @throws IllegalArgumentException if {@code stream} contains a
+     *     malformed Unicode escape sequence.
+     * @throws MalformedInputException if the system property
+     *     {@code java.util.PropertyResourceBundle.encoding} is set to "UTF-8"
+     *     and {@code stream} contains an invalid UTF-8 byte sequence.
+     * @throws UnmappableCharacterException if the system property
+     *     {@code java.util.PropertyResourceBundle.encoding} is set to "UTF-8"
+     *     and {@code stream} contains an unmappable UTF-8 byte sequence.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (InputStream stream) throws IOException {
+        // Android-changed: keep old behaviour which uses ISO-8859-1 by default.
+        // TODO(b/259671905): revert this patch once verified that it's safe.
+        /*
+        this(new InputStreamReader(stream,
+            "ISO-8859-1".equals(encoding) ?
+                ISO_8859_1.INSTANCE.newDecoder() :
+                new PropertyResourceBundleCharset("UTF-8".equals(encoding)).newDecoder()));
+        */
+        Properties properties = new Properties();
+        properties.load(stream);
+        lookup = new HashMap(properties);
+    }
+
+    /**
+     * Creates a property resource bundle from a {@link java.io.Reader
+     * Reader}.  Unlike the constructor
+     * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
+     * there is no limitation as to the encoding of the input property file.
+     *
+     * @param reader a Reader that represents a property file to
+     *        read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code reader} is null
+     * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+     *     from {@code reader}.
+     * @since 1.6
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (Reader reader) throws IOException {
+        Properties properties = new Properties();
+        properties.load(reader);
+        lookup = new HashMap(properties);
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public Object handleGetObject(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key);
+    }
+
+    /**
+     * Returns an {@code Enumeration} of the keys contained in
+     * this {@code ResourceBundle} and its parent bundles.
+     *
+     * @return an {@code Enumeration} of the keys contained in
+     *         this {@code ResourceBundle} and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a {@code Set} of the keys contained
+     * <em>only</em> in this {@code ResourceBundle}.
+     *
+     * @return a {@code Set} of the keys contained only in this
+     *         {@code ResourceBundle}
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        return lookup.keySet();
+    }
+
+    // ==================privates====================
+    private final Map<String,Object> lookup;
+}
diff --git a/android-35/java/util/Queue.java b/android-35/java/util/Queue.java
new file mode 100644
index 0000000..a3ff4be
--- /dev/null
+++ b/android-35/java/util/Queue.java
@@ -0,0 +1,212 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A collection designed for holding elements prior to processing.
+ * Besides basic {@link Collection} operations, queues provide
+ * additional insertion, extraction, and inspection operations.
+ * Each of these methods exists in two forms: one throws an exception
+ * if the operation fails, the other returns a special value (either
+ * {@code null} or {@code false}, depending on the operation).  The
+ * latter form of the insert operation is designed specifically for
+ * use with capacity-restricted {@code Queue} implementations; in most
+ * implementations, insert operations cannot fail.
+ *
+ * <table class="striped">
+ * <caption>Summary of Queue methods</caption>
+ *  <thead>
+ *  <tr>
+ *    <td></td>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Returns special value</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *    <th scope="row">Insert</th>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">Remove</th>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #poll() poll()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row">Examine</th>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #peek() peek()}</td>
+ *  </tr>
+ *  </tbody>
+ * </table>
+ *
+ * <p>Queues typically, but do not necessarily, order elements in a
+ * FIFO (first-in-first-out) manner.  Among the exceptions are
+ * priority queues, which order elements according to a supplied
+ * comparator, or the elements' natural ordering, and LIFO queues (or
+ * stacks) which order the elements LIFO (last-in-first-out).
+ * Whatever the ordering used, the <em>head</em> of the queue is that
+ * element which would be removed by a call to {@link #remove()} or
+ * {@link #poll()}.  In a FIFO queue, all new elements are inserted at
+ * the <em>tail</em> of the queue. Other kinds of queues may use
+ * different placement rules.  Every {@code Queue} implementation
+ * must specify its ordering properties.
+ *
+ * <p>The {@link #offer offer} method inserts an element if possible,
+ * otherwise returning {@code false}.  This differs from the {@link
+ * java.util.Collection#add Collection.add} method, which can fail to
+ * add an element only by throwing an unchecked exception.  The
+ * {@code offer} method is designed for use when failure is a normal,
+ * rather than exceptional occurrence, for example, in fixed-capacity
+ * (or &quot;bounded&quot;) queues.
+ *
+ * <p>The {@link #remove()} and {@link #poll()} methods remove and
+ * return the head of the queue.
+ * Exactly which element is removed from the queue is a
+ * function of the queue's ordering policy, which differs from
+ * implementation to implementation. The {@code remove()} and
+ * {@code poll()} methods differ only in their behavior when the
+ * queue is empty: the {@code remove()} method throws an exception,
+ * while the {@code poll()} method returns {@code null}.
+ *
+ * <p>The {@link #element()} and {@link #peek()} methods return, but do
+ * not remove, the head of the queue.
+ *
+ * <p>The {@code Queue} interface does not define the <i>blocking queue
+ * methods</i>, which are common in concurrent programming.  These methods,
+ * which wait for elements to appear or for space to become available, are
+ * defined in the {@link java.util.concurrent.BlockingQueue} interface, which
+ * extends this interface.
+ *
+ * <p>{@code Queue} implementations generally do not allow insertion
+ * of {@code null} elements, although some implementations, such as
+ * {@link LinkedList}, do not prohibit insertion of {@code null}.
+ * Even in the implementations that permit it, {@code null} should
+ * not be inserted into a {@code Queue}, as {@code null} is also
+ * used as a special return value by the {@code poll} method to
+ * indicate that the queue contains no elements.
+ *
+ * <p>{@code Queue} implementations generally do not define
+ * element-based versions of methods {@code equals} and
+ * {@code hashCode} but instead inherit the identity based versions
+ * from class {@code Object}, because element-based equality is not
+ * always well-defined for queues with the same elements but different
+ * ordering properties.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface Queue<E> extends Collection<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @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 and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to {@link #add}, which can fail to insert an element only
+     * by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, 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 and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll() poll()} only in that it throws an exception if
+     * this queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception
+     * if this queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E peek();
+}
diff --git a/android-35/java/util/Random.java b/android-35/java/util/Random.java
new file mode 100644
index 0000000..6add25c
--- /dev/null
+++ b/android-35/java/util/Random.java
@@ -0,0 +1,1010 @@
+/*
+ * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import java.io.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.random.RandomGenerator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+
+import jdk.internal.util.random.RandomSupport;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+
+import static jdk.internal.util.random.RandomSupport.*;
+
+import jdk.internal.misc.Unsafe;
+
+/**
+ * An instance of this class is used to generate a stream of
+ * pseudorandom numbers; its period is only 2<sup>48</sup>.
+ * The class uses a 48-bit seed, which is
+ * modified using a linear congruential formula. (See Donald E. Knuth,
+ * <cite>The Art of Computer Programming, Volume 2, Third
+ * edition: Seminumerical Algorithms</cite>, Section 3.2.1.)
+ * <p>
+ * If two instances of {@code Random} are created with the same
+ * seed, and the same sequence of method calls is made for each, they
+ * will generate and return identical sequences of numbers. In order to
+ * guarantee this property, particular algorithms are specified for the
+ * class {@code Random}. Java implementations must use all the algorithms
+ * shown here for the class {@code Random}, for the sake of absolute
+ * portability of Java code. However, subclasses of class {@code Random}
+ * are permitted to use other algorithms, so long as they adhere to the
+ * general contracts for all the methods.
+ * <p>
+ * The algorithms implemented by class {@code Random} use a
+ * {@code protected} utility method that on each invocation can supply
+ * up to 32 pseudorandomly generated bits.
+ * <p>
+ * Many applications will find the method {@link Math#random} simpler to use.
+ *
+ * <p>Instances of {@code java.util.Random} are threadsafe.
+ * However, the concurrent use of the same {@code java.util.Random}
+ * instance across threads may encounter contention and consequent
+ * poor performance. Consider instead using
+ * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded
+ * designs.
+ *
+ * <p>Instances of {@code java.util.Random} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom} to
+ * get a cryptographically secure pseudo-random number generator for use
+ * by security-sensitive applications.
+ *
+ * @author  Frank Yellin
+ * @since   1.0
+ */
+@SuppressWarnings("exports")
+@RandomGeneratorProperties(
+        name = "Random",
+        i = 48, j = 0, k = 0,
+        equidistribution = 0
+)
+public class Random implements RandomGenerator, java.io.Serializable {
+    /** use serialVersionUID from JDK 1.1 for interoperability */
+    @java.io.Serial
+    static final long serialVersionUID = 3905348978240129619L;
+
+    /**
+     * The internal state associated with this pseudorandom number generator.
+     * (The specs for the methods in this class describe the ongoing
+     * computation of this value.)
+     */
+    private final AtomicLong seed;
+
+    private static final long multiplier = 0x5DEECE66DL;
+    private static final long addend = 0xBL;
+    private static final long mask = (1L << 48) - 1;
+
+    private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+    // Android-added: flag to keep old behaviour of Random.ints().
+    /**
+     * After https://bugs.openjdk.org/browse/JDK-8301574 ints()
+     * and long() methods generate different sequence of number
+     * than nextInt() and nextLong() calls would.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.VANILLA_ICE_CREAM)
+    public static final long STREAM_INT_DIFFERS_FROM_NEXT_INT = 308103782L;
+
+    /**
+     * Creates a new random number generator. This constructor sets
+     * the seed of the random number generator to a value very likely
+     * to be distinct from any other invocation of this constructor.
+     */
+    public Random() {
+        this(seedUniquifier() ^ System.nanoTime());
+    }
+
+    private static long seedUniquifier() {
+        // L'Ecuyer, "Tables of Linear Congruential Generators of
+        // Different Sizes and Good Lattice Structure", 1999
+        for (;;) {
+            long current = seedUniquifier.get();
+            long next = current * 1181783497276652981L;
+            if (seedUniquifier.compareAndSet(current, next))
+                return next;
+        }
+    }
+
+    private static final AtomicLong seedUniquifier
+            = new AtomicLong(8682522807148012L);
+
+    /**
+     * Creates a new random number generator using a single {@code long} seed.
+     * The seed is the initial value of the internal state of the pseudorandom
+     * number generator which is maintained by method {@link #next}.
+     *
+     * @implSpec The invocation {@code new Random(seed)} is equivalent to:
+     * <pre>{@code
+     * Random rnd = new Random();
+     * rnd.setSeed(seed);
+     * }</pre>
+     *
+     * @param seed the initial seed
+     * @see   #setSeed(long)
+     */
+    public Random(long seed) {
+        if (getClass() == Random.class)
+            this.seed = new AtomicLong(initialScramble(seed));
+        else {
+            // subclass might have overridden setSeed
+            this.seed = new AtomicLong();
+            setSeed(seed);
+        }
+    }
+
+    private static long initialScramble(long seed) {
+        return (seed ^ multiplier) & mask;
+    }
+
+    /**
+     * Sets the seed of this random number generator using a single
+     * {@code long} seed. The general contract of {@code setSeed} is
+     * that it alters the state of this random number generator object
+     * so as to be in exactly the same state as if it had just been
+     * created with the argument {@code seed} as a seed. The method
+     * {@code setSeed} is implemented by class {@code Random} by
+     * atomically updating the seed to
+     *  <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
+     * and clearing the {@code haveNextNextGaussian} flag used by {@link
+     * #nextGaussian}.
+     *
+     * <p>The implementation of {@code setSeed} by class {@code Random}
+     * happens to use only 48 bits of the given seed. In general, however,
+     * an overriding method may use all 64 bits of the {@code long}
+     * argument as a seed value.
+     *
+     * @param seed the initial seed
+     */
+    public synchronized void setSeed(long seed) {
+        this.seed.set(initialScramble(seed));
+        haveNextNextGaussian = false;
+    }
+
+    /**
+     * Generates the next pseudorandom number. Subclasses should
+     * override this, as this is used by all other methods.
+     *
+     * <p>The general contract of {@code next} is that it returns an
+     * {@code int} value and if the argument {@code bits} is between
+     * {@code 1} and {@code 32} (inclusive), then that many low-order
+     * bits of the returned value will be (approximately) independently
+     * chosen bit values, each of which is (approximately) equally
+     * likely to be {@code 0} or {@code 1}. The method {@code next} is
+     * implemented by class {@code Random} by atomically updating the seed to
+     *  <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
+     * and returning
+     *  <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
+     *
+     * This is a linear congruential pseudorandom number generator, as
+     * defined by D. H. Lehmer and described by Donald E. Knuth in
+     * <cite>The Art of Computer Programming, Volume 2, Third edition:
+     * Seminumerical Algorithms</cite>, section 3.2.1.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     * @since  1.1
+     */
+    protected int next(int bits) {
+        long oldseed, nextseed;
+        AtomicLong seed = this.seed;
+        do {
+            oldseed = seed.get();
+            nextseed = (oldseed * multiplier + addend) & mask;
+        } while (!seed.compareAndSet(oldseed, nextseed));
+        return (int)(nextseed >>> (48 - bits));
+    }
+
+    /**
+     * Generates random bytes and places them into a user-supplied
+     * byte array.  The number of random bytes produced is equal to
+     * the length of the byte array.
+     *
+     * @implSpec The method {@code nextBytes} is
+     * implemented by class {@code Random} as if by:
+     * <pre>{@code
+     * public void nextBytes(byte[] bytes) {
+     *   for (int i = 0; i < bytes.length; )
+     *     for (int rnd = nextInt(), n = Math.min(bytes.length - i, 4);
+     *          n-- > 0; rnd >>= 8)
+     *       bytes[i++] = (byte)rnd;
+     * }}</pre>
+     *
+     * @param  bytes the byte array to fill with random bytes
+     * @throws NullPointerException if the byte array is null
+     * @since  1.1
+     */
+    @Override
+    public void nextBytes(byte[] bytes) {
+        for (int i = 0, len = bytes.length; i < len; )
+            for (int rnd = nextInt(),
+                 n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
+                 n-- > 0; rnd >>= Byte.SIZE)
+                bytes[i++] = (byte)rnd;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code int}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextInt} is that one {@code int} value is
+     * pseudorandomly generated and returned. All 2<sup>32</sup> possible
+     * {@code int} values are produced with (approximately) equal probability.
+     *
+     * @implSpec The method {@code nextInt} is
+     * implemented by class {@code Random} as if by:
+     * <pre>{@code
+     * public int nextInt() {
+     *   return next(32);
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value from this random number generator's sequence
+     */
+    @Override
+    public int nextInt() {
+        return next(32);
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed {@code int} value
+     * between 0 (inclusive) and the specified value (exclusive), drawn from
+     * this random number generator's sequence.  The general contract of
+     * {@code nextInt} is that one {@code int} value in the specified range
+     * is pseudorandomly generated and returned.  All {@code bound} possible
+     * {@code int} values are produced with (approximately) equal
+     * probability.
+     *
+     * @implSpec The method {@code nextInt(int bound)} is implemented by
+     * class {@code Random} as if by:
+     * <pre>{@code
+     * public int nextInt(int bound) {
+     *   if (bound <= 0)
+     *     throw new IllegalArgumentException("bound must be positive");
+     *
+     *   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
+     *     return (int)((bound * (long)next(31)) >> 31);
+     *
+     *   int bits, val;
+     *   do {
+     *       bits = next(31);
+     *       val = bits % bound;
+     *   } while (bits - val + (bound-1) < 0);
+     *   return val;
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits.  If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code int}
+     * values from the stated range with perfect uniformity.
+     * <p>
+     * The algorithm is slightly tricky.  It rejects values that would result
+     * in an uneven distribution (due to the fact that 2^31 is not divisible
+     * by n). The probability of a value being rejected depends on n.  The
+     * worst case is n=2^30+1, for which the probability of a reject is 1/2,
+     * and the expected number of iterations before the loop terminates is 2.
+     * <p>
+     * The algorithm treats the case where n is a power of two specially: it
+     * returns the correct number of high-order bits from the underlying
+     * pseudo-random number generator.  In the absence of special treatment,
+     * the correct number of <i>low-order</i> bits would be returned.  Linear
+     * congruential pseudo-random number generators such as the one
+     * implemented by this class are known to have short periods in the
+     * sequence of values of their low-order bits.  Thus, this special case
+     * greatly increases the length of the sequence of values returned by
+     * successive calls to this method if n is a small power of two.
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value between zero (inclusive) and {@code bound} (exclusive)
+     *         from this random number generator's sequence
+     * @throws IllegalArgumentException if bound is not positive
+     * @since 1.2
+     */
+    @Override
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        int r = next(31);
+        int m = bound - 1;
+        if ((bound & m) == 0)  // i.e., bound is a power of 2
+            r = (int)((bound * (long)r) >> 31);
+        else { // reject over-represented candidates
+            for (int u = r;
+                 u - (r = u % bound) + m < 0;
+                 u = next(31))
+                ;
+        }
+        return r;
+    }
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code long}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextLong} is that one {@code long} value is
+     * pseudorandomly generated and returned.
+     *
+     * @implSpec The method {@code nextLong} is implemented by class {@code Random}
+     * as if by:
+     * <pre>{@code
+     * public long nextLong() {
+     *   return ((long)next(32) << 32) + next(32);
+     * }}</pre>
+     *
+     * Because class {@code Random} uses a seed with only 48 bits,
+     * this algorithm will not return all possible {@code long} values.
+     *
+     * @return the next pseudorandom, uniformly distributed {@code long}
+     *         value from this random number generator's sequence
+     */
+    @Override
+    public long nextLong() {
+        // it's okay that the bottom word remains signed.
+        return ((long)(next(32)) << 32) + next(32);
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code boolean} value from this random number generator's
+     * sequence. The general contract of {@code nextBoolean} is that one
+     * {@code boolean} value is pseudorandomly generated and returned.  The
+     * values {@code true} and {@code false} are produced with
+     * (approximately) equal probability.
+     *
+     * @implSpec The method {@code nextBoolean} is implemented by class
+     * {@code Random} as if by:
+     * <pre>{@code
+     * public boolean nextBoolean() {
+     *   return next(1) != 0;
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed
+     *         {@code boolean} value from this random number generator's
+     *         sequence
+     * @since 1.2
+     */
+    @Override
+    public boolean nextBoolean() {
+        return next(1) != 0;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code float}
+     * value between {@code 0.0} and {@code 1.0} from this random
+     * number generator's sequence.
+     *
+     * <p>The general contract of {@code nextFloat} is that one
+     * {@code float} value, chosen (approximately) uniformly from the
+     * range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
+     * pseudorandomly generated and returned. All 2<sup>24</sup> possible
+     * {@code float} values of the form <i>m&nbsp;x&nbsp;</i>2<sup>-24</sup>,
+     * where <i>m</i> is a positive integer less than 2<sup>24</sup>, are
+     * produced with (approximately) equal probability.
+     *
+     * @implSpec The method {@code nextFloat} is implemented by class
+     * {@code Random} as if by:
+     * <pre>{@code
+     * public float nextFloat() {
+     *   return next(24) / ((float)(1 << 24));
+     * }}</pre>
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code float}
+     * values from the stated range with perfect uniformity.<p>
+     * [In early versions of Java, the result was incorrectly calculated as:
+     *  <pre> {@code return next(30) / ((float)(1 << 30));}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a slight nonuniformity because of the bias in the rounding
+     * of floating-point numbers: it was slightly more likely that the
+     * low-order bit of the significand would be 0 than that it would be 1.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code float}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     */
+    @Override
+    public float nextFloat() {
+        return next(24) / ((float)(1 << 24));
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code double} value between {@code 0.0} and
+     * {@code 1.0} from this random number generator's sequence.
+     *
+     * <p>The general contract of {@code nextDouble} is that one
+     * {@code double} value, chosen (approximately) uniformly from the
+     * range {@code 0.0d} (inclusive) to {@code 1.0d} (exclusive), is
+     * pseudorandomly generated and returned.
+     *
+     * @implSpec The method {@code nextDouble} is implemented by class
+     * {@code Random} as if by:
+     * <pre>{@code
+     * public double nextDouble() {
+     *   return (((long)next(26) << 27) + next(27))
+     *     / (double)(1L << 53);
+     * }}</pre>
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the {@code next} method is only approximately an unbiased source
+     * of independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code double} values
+     * from the stated range with perfect uniformity.
+     * <p>[In early versions of Java, the result was incorrectly calculated as:
+     * <pre> {@code return (((long)next(27) << 27) + next(27)) / (double)(1L << 54);}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a large nonuniformity because of the bias in the rounding of
+     * floating-point numbers: it was three times as likely that the low-order
+     * bit of the significand would be 0 than that it would be 1! This
+     * nonuniformity probably doesn't matter much in practice, but we strive
+     * for perfection.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code double}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     * @see Math#random
+     */
+    @Override
+    public double nextDouble() {
+        return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
+    }
+
+    private double nextNextGaussian;
+    private boolean haveNextNextGaussian = false;
+
+    /**
+     * Returns the next pseudorandom, Gaussian ("normally") distributed
+     * {@code double} value with mean {@code 0.0} and standard
+     * deviation {@code 1.0} from this random number generator's sequence.
+     * <p>
+     * The general contract of {@code nextGaussian} is that one
+     * {@code double} value, chosen from (approximately) the usual
+     * normal distribution with mean {@code 0.0} and standard deviation
+     * {@code 1.0}, is pseudorandomly generated and returned.
+     *
+     * @implSpec The method {@code nextGaussian} is implemented by class
+     * {@code Random} as if by a threadsafe version of the following:
+     * <pre>{@code
+     * private double nextNextGaussian;
+     * private boolean haveNextNextGaussian = false;
+     *
+     * public double nextGaussian() {
+     *   if (haveNextNextGaussian) {
+     *     haveNextNextGaussian = false;
+     *     return nextNextGaussian;
+     *   } else {
+     *     double v1, v2, s;
+     *     do {
+     *       v1 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       v2 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       s = v1 * v1 + v2 * v2;
+     *     } while (s >= 1 || s == 0);
+     *     double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+     *     nextNextGaussian = v2 * multiplier;
+     *     haveNextNextGaussian = true;
+     *     return v1 * multiplier;
+     *   }
+     * }}</pre>
+     *
+     * This uses the <i>polar method</i> of G. E. P. Box, M. E. Muller, and
+     * G. Marsaglia, as described by Donald E. Knuth in <cite>The Art of
+     * Computer Programming, Volume 2, third edition: Seminumerical Algorithms</cite>,
+     * section 3.4.1, subsection C, algorithm P. Note that it generates two
+     * independent values at the cost of only one call to {@code StrictMath.log}
+     * and one call to {@code StrictMath.sqrt}.
+     *
+     * @return the next pseudorandom, Gaussian ("normally") distributed
+     *         {@code double} value with mean {@code 0.0} and
+     *         standard deviation {@code 1.0} from this random number
+     *         generator's sequence
+     */
+    @Override
+    public synchronized double nextGaussian() {
+        // See Knuth, TAOCP, Vol. 2, 3rd edition, Section 3.4.1 Algorithm C.
+        if (haveNextNextGaussian) {
+            haveNextNextGaussian = false;
+            return nextNextGaussian;
+        } else {
+            double v1, v2, s;
+            do {
+                v1 = 2 * nextDouble() - 1; // between -1 and 1
+                v2 = 2 * nextDouble() - 1; // between -1 and 1
+                s = v1 * v1 + v2 * v2;
+            } while (s >= 1 || s == 0);
+            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+            nextNextGaussian = v2 * multiplier;
+            haveNextNextGaussian = true;
+            return v1 * multiplier;
+        }
+    }
+
+    /**
+     * Serializable fields for Random.
+     *
+     * @serialField    seed long
+     *              seed for random computations
+     * @serialField    nextNextGaussian double
+     *              next Gaussian to be returned
+     * @serialField      haveNextNextGaussian boolean
+     *              nextNextGaussian is valid
+     */
+    @java.io.Serial
+    private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("seed", Long.TYPE),
+            new ObjectStreamField("nextNextGaussian", Double.TYPE),
+            new ObjectStreamField("haveNextNextGaussian", Boolean.TYPE)
+    };
+
+    /**
+     * Reconstitute the {@code Random} instance from a stream (that is,
+     * deserialize it).
+     *
+     * @param  s the {@code ObjectInputStream} from which data is read
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // The seed is read in as {@code long} for
+        // historical reasons, but it is converted to an AtomicLong.
+        long seedVal = fields.get("seed", -1L);
+        if (seedVal < 0)
+            throw new java.io.StreamCorruptedException(
+                    "Random: invalid seed");
+        resetSeed(seedVal);
+        nextNextGaussian = fields.get("nextNextGaussian", 0.0);
+        haveNextNextGaussian = fields.get("haveNextNextGaussian", false);
+    }
+
+    /**
+     * Save the {@code Random} instance to a stream.
+     *
+     * @param  s the {@code ObjectOutputStream} to which data is written
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    @java.io.Serial
+    private synchronized void writeObject(ObjectOutputStream s)
+            throws IOException {
+
+        // set the values of the Serializable fields
+        ObjectOutputStream.PutField fields = s.putFields();
+
+        // The seed is serialized as a long for historical reasons.
+        fields.put("seed", seed.get());
+        fields.put("nextNextGaussian", nextNextGaussian);
+        fields.put("haveNextNextGaussian", haveNextNextGaussian);
+
+        // save them
+        s.writeFields();
+    }
+
+    // Support for resetting seed while deserializing
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final long seedOffset;
+    static {
+        try {
+            seedOffset = unsafe.objectFieldOffset
+                    (Random.class.getDeclaredField("seed"));
+        } catch (Exception ex) { throw new Error(ex); }
+    }
+    private void resetSeed(long seedVal) {
+        unsafe.putReferenceVolatile(this, seedOffset, new AtomicLong(seedVal));
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(long streamSize) {
+        return AbstractSpliteratorGenerator.ints(this, streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints() {
+        // Android-changed: keep old behaviour for apps targeting already released
+        // platforms.
+        // return AbstractSpliteratorGenerator.ints(this);
+        if (VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM &&
+            Compatibility.isChangeEnabled(STREAM_INT_DIFFERS_FROM_NEXT_INT)) {
+            return AbstractSpliteratorGenerator.ints(this);
+        } else {
+            return IntStream.generate(this::nextInt);
+        }
+    }
+
+    // Android-added: implementation specified in ints(long, int, int) javadoc.
+    private int boundedNextInt(int origin, int bound) {
+        int n = bound - origin;
+        if (n > 0) {
+            return nextInt(n) + origin;
+        } else {  // range not representable as int
+            int r;
+            do {
+                r = nextInt();
+            } while (r < origin || r >= bound);
+            return r;
+        }
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) {
+        // Android-changed: keep old behaviour for apps targeting already released
+        // platforms.
+        // return AbstractSpliteratorGenerator.ints(this, streamSize, randomNumberOrigin, randomNumberBound);
+        if (VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM &&
+            Compatibility.isChangeEnabled(STREAM_INT_DIFFERS_FROM_NEXT_INT)) {
+            return AbstractSpliteratorGenerator.ints(this, streamSize, randomNumberOrigin, randomNumberBound);
+        } else {
+            RandomSupport.checkStreamSize(streamSize);
+            RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+            return IntStream
+                .generate(() -> boundedNextInt(randomNumberOrigin, randomNumberBound))
+                .limit(streamSize);
+        }
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        // Android-changed: keep old behaviour for apps targeting already released
+        // platforms.
+        // return AbstractSpliteratorGenerator.ints(this, randomNumberOrigin, randomNumberBound);
+        if (VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM &&
+            Compatibility.isChangeEnabled(STREAM_INT_DIFFERS_FROM_NEXT_INT)) {
+            return AbstractSpliteratorGenerator.ints(this, randomNumberOrigin, randomNumberBound);
+        } else {
+            RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+            return IntStream.generate(() -> boundedNextInt(randomNumberOrigin, randomNumberBound));
+        }
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long streamSize) {
+        return AbstractSpliteratorGenerator.longs(this, streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs() {
+        return AbstractSpliteratorGenerator.longs(this);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long streamSize, long randomNumberOrigin, long randomNumberBound) {
+        return AbstractSpliteratorGenerator.longs(this, streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        return AbstractSpliteratorGenerator.longs(this, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(long streamSize) {
+        return AbstractSpliteratorGenerator.doubles(this, streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles() {
+        return AbstractSpliteratorGenerator.doubles(this);
+    }
+
+   /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is less than zero,
+     *         or {@code randomNumberOrigin} is not finite,
+     *         or {@code randomNumberBound} is not finite, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
+        return AbstractSpliteratorGenerator.doubles(this, streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        return AbstractSpliteratorGenerator.doubles(this, randomNumberOrigin, randomNumberBound);
+    }
+}
diff --git a/android-35/java/util/RandomAccess.java b/android-35/java/util/RandomAccess.java
new file mode 100644
index 0000000..52de56d
--- /dev/null
+++ b/android-35/java/util/RandomAccess.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Marker interface used by {@code List} implementations to indicate that
+ * they support fast (generally constant time) random access.  The primary
+ * purpose of this interface is to allow generic algorithms to alter their
+ * behavior to provide good performance when applied to either random or
+ * sequential access lists.
+ *
+ * <p>The best algorithms for manipulating random access lists (such as
+ * {@code ArrayList}) can produce quadratic behavior when applied to
+ * sequential access lists (such as {@code LinkedList}).  Generic list
+ * algorithms are encouraged to check whether the given list is an
+ * {@code instanceof} this interface before applying an algorithm that would
+ * provide poor performance if it were applied to a sequential access list,
+ * and to alter their behavior if necessary to guarantee acceptable
+ * performance.
+ *
+ * <p>It is recognized that the distinction between random and sequential
+ * access is often fuzzy.  For example, some {@code List} implementations
+ * provide asymptotically linear access times if they get huge, but constant
+ * access times in practice.  Such a {@code List} implementation
+ * should generally implement this interface.  As a rule of thumb, a
+ * {@code List} implementation should implement this interface if,
+ * for typical instances of the class, this loop:
+ * <pre>
+ *     for (int i=0, n=list.size(); i &lt; n; i++)
+ *         list.get(i);
+ * </pre>
+ * runs faster than this loop:
+ * <pre>
+ *     for (Iterator i=list.iterator(); i.hasNext(); )
+ *         i.next();
+ * </pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.4
+ */
+public interface RandomAccess {
+}
diff --git a/android-35/java/util/RegularEnumSet.java b/android-35/java/util/RegularEnumSet.java
new file mode 100644
index 0000000..1deda8a
--- /dev/null
+++ b/android-35/java/util/RegularEnumSet.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "regular sized" enum types
+ * (i.e., those with 64 or fewer enum constants).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    @java.io.Serial
+    private static final long serialVersionUID = 3411599620347842686L;
+    /**
+     * Bit vector representation of this set.  The 2^k bit indicates the
+     * presence of universe[k] in this set.
+     */
+    private long elements = 0L;
+
+    RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+    }
+
+    void addRange(E from, E to) {
+        elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
+    }
+
+    void addAll() {
+        if (universe.length != 0)
+            elements = -1L >>> -universe.length;
+    }
+
+    void complement() {
+        if (universe.length != 0) {
+            elements = ~elements;
+            elements &= -1L >>> -universe.length;  // Mask unused bits
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "snapshot" iterator that will never throw {@link
+     * ConcurrentModificationException}; the elements are traversed as they
+     * existed when this call was invoked.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the set not yet
+         * returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        EnumSetIterator() {
+            unseen = elements;
+        }
+
+        public boolean hasNext() {
+            return unseen != 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (unseen == 0)
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            unseen -= lastReturned;
+            return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            elements &= ~lastReturned;
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return Long.bitCount(elements);
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return elements == 0;
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if the set changed as a result of the call
+     *
+     * @throws NullPointerException if {@code e} is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        long oldElements = elements;
+        elements |= (1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return {@code true} if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~(1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet<?> es))
+            return super.containsAll(c);
+
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        return (es.elements & ~elements) == 0;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *     of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof RegularEnumSet<?> es))
+            return super.addAll(c);
+
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        long oldElements = elements;
+        elements |= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet<?> es))
+            return super.removeAll(c);
+
+        if (es.elementType != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet<?> es))
+            return super.retainAll(c);
+
+        if (es.elementType != elementType) {
+            boolean changed = (elements != 0);
+            elements = 0;
+            return changed;
+        }
+
+        long oldElements = elements;
+        elements &= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        elements = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof RegularEnumSet<?> es))
+            return super.equals(o);
+
+        if (es.elementType != elementType)
+            return elements == 0 && es.elements == 0;
+        return es.elements == elements;
+    }
+}
diff --git a/android-35/java/util/ResourceBundle.java b/android-35/java/util/ResourceBundle.java
new file mode 100644
index 0000000..f8799e4
--- /dev/null
+++ b/android-35/java/util/ResourceBundle.java
@@ -0,0 +1,3774 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.jar.JarEntry;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import sun.security.action.GetPropertyAction;
+import sun.util.locale.BaseLocale;
+import sun.util.locale.LocaleObjectCache;
+
+// Android-removed: Support for ResourceBundleControlProvider.
+// Removed references to ResourceBundleControlProvider from the documentation.
+// The service provider interface ResourceBundleControlProvider is not
+// available on Android.
+// Android-removed: Mentions of modules as they are not supported.
+/**
+ *
+ * Resource bundles contain locale-specific objects.  When your program needs a
+ * locale-specific resource, a <code>String</code> for example, your program can
+ * load it from the resource bundle that is appropriate for the current user's
+ * locale. In this way, you can write program code that is largely independent
+ * of the user's locale isolating most, if not all, of the locale-specific
+ * information in resource bundles.
+ *
+ * <p>
+ * This allows you to write programs that can:
+ * <UL>
+ * <LI> be easily localized, or translated, into different languages
+ * <LI> handle multiple locales at once
+ * <LI> be easily modified later to support even more locales
+ * </UL>
+ *
+ * <P>
+ * Resource bundles belong to families whose members share a common base
+ * name, but whose names also have additional components that identify
+ * their locales. For example, the base name of a family of resource
+ * bundles might be "MyResources". The family should have a default
+ * resource bundle which simply has the same name as its family -
+ * "MyResources" - and will be used as the bundle of last resort if a
+ * specific locale is not supported. The family can then provide as
+ * many locale-specific members as needed, for example a German one
+ * named "MyResources_de".
+ *
+ * <P>
+ * Each resource bundle in a family contains the same items, but the items have
+ * been translated for the locale represented by that resource bundle.
+ * For example, both "MyResources" and "MyResources_de" may have a
+ * <code>String</code> that's used on a button for canceling operations.
+ * In "MyResources" the <code>String</code> may contain "Cancel" and in
+ * "MyResources_de" it may contain "Abbrechen".
+ *
+ * <P>
+ * If there are different resources for different countries, you
+ * can make specializations: for example, "MyResources_de_CH" contains objects for
+ * the German language (de) in Switzerland (CH). If you want to only
+ * modify some of the resources
+ * in the specialization, you can do so.
+ *
+ * <P>
+ * When your program needs a locale-specific object, it loads
+ * the <code>ResourceBundle</code> class using the
+ * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
+ * method:
+ * <blockquote>
+ * <pre>
+ * ResourceBundle myResources =
+ *      ResourceBundle.getBundle("MyResources", currentLocale);
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * Resource bundles contain key/value pairs. The keys uniquely
+ * identify a locale-specific object in the bundle. Here's an
+ * example of a <code>ListResourceBundle</code> that contains
+ * two key/value pairs:
+ * <blockquote>
+ * <pre>
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *             // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
+ *             {"OkKey", "OK"},
+ *             {"CancelKey", "Cancel"},
+ *             // END OF MATERIAL TO LOCALIZE
+ *        };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * Keys are always <code>String</code>s.
+ * In this example, the keys are "OkKey" and "CancelKey".
+ * In the above example, the values
+ * are also <code>String</code>s--"OK" and "Cancel"--but
+ * they don't have to be. The values can be any type of object.
+ *
+ * <P>
+ * You retrieve an object from resource bundle using the appropriate
+ * getter method. Because "OkKey" and "CancelKey"
+ * are both strings, you would use <code>getString</code> to retrieve them:
+ * <blockquote>
+ * <pre>
+ * button1 = new Button(myResources.getString("OkKey"));
+ * button2 = new Button(myResources.getString("CancelKey"));
+ * </pre>
+ * </blockquote>
+ * The getter methods all require the key as an argument and return
+ * the object if found. If the object is not found, the getter method
+ * throws a <code>MissingResourceException</code>.
+ *
+ * <P>
+ * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
+ * a method for getting string arrays, <code>getStringArray</code>,
+ * as well as a generic <code>getObject</code> method for any other
+ * type of object. When using <code>getObject</code>, you'll
+ * have to cast the result to the appropriate type. For example:
+ * <blockquote>
+ * <pre>
+ * int[] myIntegers = (int[]) myResources.getObject("intList");
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
+ * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
+ * that provide a fairly simple way to create resources.
+ * As you saw briefly in a previous example, <code>ListResourceBundle</code>
+ * manages its resource as a list of key/value pairs.
+ * <code>PropertyResourceBundle</code> uses a properties file to manage
+ * its resources.
+ *
+ * <p>
+ * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
+ * do not suit your needs, you can write your own <code>ResourceBundle</code>
+ * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
+ * and <code>getKeys()</code>.
+ *
+ * <p>
+ * The implementation of a {@code ResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the non-abstract methods in this class, and the methods in the direct
+ * known concrete subclasses {@code ListResourceBundle} and
+ * {@code PropertyResourceBundle} are thread-safe.
+ *
+ * <h3>ResourceBundle.Control</h3>
+ *
+ * The {@link ResourceBundle.Control} class provides information necessary
+ * to perform the bundle loading process by the <code>getBundle</code>
+ * factory methods that take a <code>ResourceBundle.Control</code>
+ * instance. You can implement your own subclass in order to enable
+ * non-standard resource bundle formats, change the search strategy, or
+ * define caching parameters. Refer to the descriptions of the class and the
+ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
+ * factory method for details.
+ *
+ * <h3>Cache Management</h3>
+ *
+ * Resource bundle instances created by the <code>getBundle</code> factory
+ * methods are cached by default, and the factory methods return the same
+ * resource bundle instance multiple times if it has been
+ * cached. <code>getBundle</code> clients may clear the cache, manage the
+ * lifetime of cached resource bundle instances using time-to-live values,
+ * or specify not to cache resource bundle instances. Refer to the
+ * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
+ * Control) <code>getBundle</code> factory method}, {@link
+ * #clearCache(ClassLoader) clearCache}, {@link
+ * Control#getTimeToLive(String, Locale)
+ * ResourceBundle.Control.getTimeToLive}, and {@link
+ * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+ * long) ResourceBundle.Control.needsReload} for details.
+ *
+ * <h3>Example</h3>
+ *
+ * The following is a very simple example of a <code>ResourceBundle</code>
+ * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
+ * resources you would probably use a <code>Map</code>).
+ * Notice that you don't need to supply a value if
+ * a "parent-level" <code>ResourceBundle</code> handles the same
+ * key with the same value (as for the okKey below).
+ * <blockquote>
+ * <pre>
+ * // default (English language, United States)
+ * public class MyResources extends ResourceBundle {
+ *     public Object handleGetObject(String key) {
+ *         if (key.equals("okKey")) return "Ok";
+ *         if (key.equals("cancelKey")) return "Cancel";
+ *         return null;
+ *     }
+ *
+ *     public Enumeration&lt;String&gt; getKeys() {
+ *         return Collections.enumeration(keySet());
+ *     }
+ *
+ *     // Overrides handleKeySet() so that the getKeys() implementation
+ *     // can rely on the keySet() value.
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("okKey", "cancelKey"));
+ *     }
+ * }
+ *
+ * // German language
+ * public class MyResources_de extends MyResources {
+ *     public Object handleGetObject(String key) {
+ *         // don't need okKey, since parent level handles it.
+ *         if (key.equals("cancelKey")) return "Abbrechen";
+ *         return null;
+ *     }
+ *
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("cancelKey"));
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * You do not have to restrict yourself to using a single family of
+ * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
+ * exception messages, <code>ExceptionResources</code>
+ * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
+ * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
+ * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
+ *
+ * @see ListResourceBundle
+ * @see PropertyResourceBundle
+ * @see MissingResourceException
+ * @since 1.1
+ * @revised 9
+ */
+public abstract class ResourceBundle {
+
+    /** initial size of the bundle cache */
+    private static final int INITIAL_CACHE_SIZE = 32;
+
+    // Android-removed: JavaUtilResourceBundleAccess is absent.
+    /*
+    static {
+        SharedSecrets.setJavaUtilResourceBundleAccess(
+            new JavaUtilResourceBundleAccess() {
+                @Override
+                public void setParent(ResourceBundle bundle,
+                                      ResourceBundle parent) {
+                    bundle.setParent(parent);
+                }
+
+                @Override
+                public ResourceBundle getParent(ResourceBundle bundle) {
+                    return bundle.parent;
+                }
+
+                @Override
+                public void setLocale(ResourceBundle bundle, Locale locale) {
+                    bundle.locale = locale;
+                }
+
+                @Override
+                public void setName(ResourceBundle bundle, String name) {
+                    bundle.name = name;
+                }
+
+                @Override
+                public ResourceBundle getBundle(String baseName, Locale locale, Module module) {
+                    // use the given module as the caller to bypass the access check
+                    return getBundleImpl(module, module,
+                                         baseName, locale,
+                                         getDefaultControl(module, baseName));
+                }
+
+                @Override
+                public ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+                    return ResourceBundleProviderHelper.newResourceBundle(bundleClass);
+                }
+            });
+    }
+    */
+
+    /** constant indicating that no resource bundle exists */
+    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
+            public Enumeration<String> getKeys() { return null; }
+            protected Object handleGetObject(String key) { return null; }
+            public String toString() { return "NONEXISTENT_BUNDLE"; }
+        };
+
+
+    /**
+     * The cache is a map from cache keys (with bundle base name, locale, and
+     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
+     * BundleReference.
+     *
+     * The cache is a ConcurrentMap, allowing the cache to be searched
+     * concurrently by multiple threads.  This will also allow the cache keys
+     * to be reclaimed along with the ClassLoaders they reference.
+     *
+     * This variable would be better named "cache", but we keep the old
+     * name for compatibility with some workarounds for bug 4212439.
+     */
+    private static final ConcurrentMap<CacheKey, BundleReference> cacheList
+        = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
+
+    /**
+     * Queue for reference objects referring to class loaders or bundles.
+     */
+    private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+    /**
+     * Returns the base name of this bundle, if known, or {@code null} if unknown.
+     *
+     * If not null, then this is the value of the {@code baseName} parameter
+     * that was passed to the {@code ResourceBundle.getBundle(...)} method
+     * when the resource bundle was loaded.
+     *
+     * @return The base name of the resource bundle, as provided to and expected
+     * by the {@code ResourceBundle.getBundle(...)} methods.
+     *
+     * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader)
+     *
+     * @since 1.8
+     */
+    public String getBaseBundleName() {
+        return name;
+    }
+
+    /**
+     * The parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     */
+    protected ResourceBundle parent = null;
+
+    /**
+     * The locale for this bundle.
+     */
+    private Locale locale = null;
+
+    /**
+     * The base bundle name for this bundle.
+     */
+    private String name;
+
+    /**
+     * The flag indicating this bundle has expired in the cache.
+     */
+    private volatile boolean expired;
+
+    /**
+     * The back link to the cache key. null if this bundle isn't in
+     * the cache (yet) or has expired.
+     */
+    private volatile CacheKey cacheKey;
+
+    /**
+     * A Set of the keys contained only in this ResourceBundle.
+     */
+    private volatile Set<String> keySet;
+
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ResourceBundle() {
+    }
+
+    /**
+     * Gets a string for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string
+     * @return the string for the given key
+     */
+    public final String getString(String key) {
+        return (String) getObject(key);
+    }
+
+    /**
+     * Gets a string array for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string array
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string array
+     * @return the string array for the given key
+     */
+    public final String[] getStringArray(String key) {
+        return (String[]) getObject(key);
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle or one of its parents.
+     * This method first tries to obtain the object from this resource bundle using
+     * {@link #handleGetObject(java.lang.String) handleGetObject}.
+     * If not successful, and the parent resource bundle is not null,
+     * it calls the parent's <code>getObject</code> method.
+     * If still not successful, it throws a MissingResourceException.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @return the object for the given key
+     */
+    public final Object getObject(String key) {
+        Object obj = handleGetObject(key);
+        if (obj == null) {
+            if (parent != null) {
+                obj = parent.getObject(key);
+            }
+            if (obj == null) {
+                throw new MissingResourceException("Can't find resource for bundle "
+                                                   +this.getClass().getName()
+                                                   +", key "+key,
+                                                   this.getClass().getName(),
+                                                   key);
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * Returns the locale of this resource bundle. This method can be used after a
+     * call to getBundle() to determine whether the resource bundle returned really
+     * corresponds to the requested locale or is a fallback.
+     *
+     * @return the locale of this resource bundle
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /*
+     * Automatic determination of the ClassLoader to be used to load
+     * resources on behalf of the client.
+     */
+    private static ClassLoader getLoader(Class<?> caller) {
+        ClassLoader cl = caller == null ? null : caller.getClassLoader();
+        if (cl == null) {
+            // When the caller's loader is the boot class loader, cl is null
+            // here. In that case, ClassLoader.getSystemClassLoader() may
+            // return the same class loader that the application is
+            // using. We therefore use a wrapper ClassLoader to create a
+            // separate scope for bundles loaded on behalf of the Java
+            // runtime so that these bundles cannot be returned from the
+            // cache to the application (5048280).
+            cl = RBClassLoader.INSTANCE;
+        }
+        return cl;
+    }
+
+    /**
+     * A wrapper of ClassLoader.getSystemClassLoader().
+     */
+    private static class RBClassLoader extends ClassLoader {
+        private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
+                new PrivilegedAction<RBClassLoader>() {
+                    public RBClassLoader run() {
+                        return new RBClassLoader();
+                    }
+                });
+        private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
+
+        private RBClassLoader() {
+        }
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            if (loader != null) {
+                return loader.loadClass(name);
+            }
+            return Class.forName(name);
+        }
+        public URL getResource(String name) {
+            if (loader != null) {
+                return loader.getResource(name);
+            }
+            return ClassLoader.getSystemResource(name);
+        }
+        public InputStream getResourceAsStream(String name) {
+            if (loader != null) {
+                return loader.getResourceAsStream(name);
+            }
+            return ClassLoader.getSystemResourceAsStream(name);
+        }
+    }
+
+    // Android-removed: modules are not supported.
+    /*
+    private static ClassLoader getLoader(Module module) {
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        return AccessController.doPrivileged(pa);
+    }
+
+    /**
+     * @param module a non-null-screened module form the {@link CacheKey#getModule()}.
+     * @return the ClassLoader to use in {@link Control#needsReload}
+     *         and {@link Control#newBundle}
+     *
+    private static ClassLoader getLoaderForControl(Module module) {
+        ClassLoader loader = getLoader(module);
+        return loader == null ? ClassLoader.getPlatformClassLoader() : loader;
+    }
+    */
+
+    /**
+     * Sets the parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     *
+     * @param parent this bundle's parent bundle.
+     */
+    protected void setParent(ResourceBundle parent) {
+        assert parent != NONEXISTENT_BUNDLE;
+        this.parent = parent;
+    }
+
+    // Android-changed: as modules are not supported keep using ClassLoader as part
+    // of CacheKey.
+    /**
+     * Key used for cached resource bundles.  The key checks the base
+     * name, the locale, and the class loader to determine if the
+     * resource is a match to the requested one. The loader may be
+     * null, but the base name and the locale must have a non-null
+     * value.
+     */
+    private static final class CacheKey {
+        // These three are the actual keys for lookup in Map.
+        private final String name;
+        private volatile Locale locale;
+        private final KeyElementReference<ClassLoader> loaderRef;
+        // Android-removed: modules are not supported.
+        /*
+        private final KeyElementReference<Module> moduleRef;
+        private final KeyElementReference<Module> callerRef;
+        // this is the part of hashCode that pertains to module and callerModule
+        // which can be GCed..
+        private final int modulesHash;
+        */
+
+        // bundle format which is necessary for calling
+        // Control.needsReload().
+        private volatile String format;
+
+        // These time values are in CacheKey so that NONEXISTENT_BUNDLE
+        // doesn't need to be cloned for caching.
+
+        // The time when the bundle has been loaded
+        private volatile long loadTime;
+
+        // The time when the bundle expires in the cache, or either
+        // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
+        private volatile long expirationTime;
+
+        // Placeholder for an error report by a Throwable
+        private volatile Throwable cause;
+
+        // Android-removed: Support for ResourceBundleControlProvider.
+        /*
+        // ResourceBundleProviders for loading ResourceBundles
+        private volatile ServiceLoader<ResourceBundleProvider> providers;
+        private volatile boolean providersChecked;
+
+        // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier.
+        private volatile Boolean callerHasProvider;
+        */
+
+        // Android-changed: keep Java 8 constructor.
+        // CacheKey(String baseName, Locale locale, Module module, Module caller) {
+        CacheKey(String baseName, Locale locale, ClassLoader loader) {
+            // Objects.requireNonNull(module);
+            // Objects.requireNonNull(caller);
+
+            this.name = baseName;
+            this.locale = locale;
+            // this.moduleRef = new KeyElementReference<>(module, referenceQueue, this);
+            // this.callerRef = new KeyElementReference<>(caller, referenceQueue, this);
+            // this.modulesHash = module.hashCode() ^ caller.hashCode();
+            if (loader == null) {
+                this.loaderRef = null;
+            } else {
+                this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this);
+            }
+        }
+
+        CacheKey(CacheKey src) {
+            // Android-removed: modules are not supported.
+            /*
+            // Create References to src's modules
+            this.moduleRef = new KeyElementReference<>(
+                Objects.requireNonNull(src.getModule()), referenceQueue, this);
+            this.callerRef = new KeyElementReference<>(
+                Objects.requireNonNull(src.getCallerModule()), referenceQueue, this);
+            */
+            // Copy fields from src. ResourceBundleProviders related fields
+            // and "cause" should not be copied.
+            this.name = src.name;
+            this.locale = src.locale;
+            if (src.loaderRef == null) {
+                this.loaderRef = null;
+            } else {
+                ClassLoader loader = src.loaderRef.get();
+                this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this);
+            }
+            // Android-removed: modules are not supported.
+            // this.modulesHash = src.modulesHash;
+            this.format = src.format;
+            this.loadTime = src.loadTime;
+            this.expirationTime = src.expirationTime;
+        }
+
+        String getName() {
+            return name;
+        }
+
+        Locale getLocale() {
+            return locale;
+        }
+
+        CacheKey setLocale(Locale locale) {
+            this.locale = locale;
+            return this;
+        }
+
+        // Android-removed: modules are not supported.
+        /*
+        Module getModule() {
+            return moduleRef.get();
+        }
+
+        Module getCallerModule() {
+            return callerRef.get();
+        }
+
+        ServiceLoader<ResourceBundleProvider> getProviders() {
+            if (!providersChecked) {
+                providers = getServiceLoader(getModule(), name);
+                providersChecked = true;
+            }
+            return providers;
+        }
+
+        boolean hasProviders() {
+            return getProviders() != null;
+        }
+
+        boolean callerHasProvider() {
+            return callerHasProvider == Boolean.TRUE;
+        }
+        */
+
+        ClassLoader getLoader() {
+            return loaderRef != null ? loaderRef.get() : null;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            try {
+                final CacheKey otherEntry = (CacheKey)other;
+                // Android-removed: modules are not supported.
+                //quick check to see if they are not equal
+                // if (modulesHash != otherEntry.modulesHash) {
+                //     return false;
+                // }
+                //are the names the same?
+                if (!name.equals(otherEntry.name)) {
+                    return false;
+                }
+                // are the locales the same?
+                if (!locale.equals(otherEntry.locale)) {
+                    return false;
+                }
+
+                //are refs (both non-null) or (both null)?
+                if (loaderRef == null) {
+                    return otherEntry.loaderRef == null;
+                }
+                ClassLoader loader = loaderRef.get();
+                return (otherEntry.loaderRef != null)
+                        // with a null reference we can no longer find
+                        // out which class loader was referenced; so
+                        // treat it as unequal
+                        && (loader != null)
+                        && (otherEntry.loaderRef.refersTo(loader));
+                // Android-removed: modules are not supported.
+                /*
+                // are modules and callerModules the same and non-null?
+                Module module = getModule();
+                Module caller = getCallerModule();
+                return ((module != null) && (module.equals(otherEntry.getModule())) &&
+                        (caller != null) && (caller.equals(otherEntry.getCallerModule())));
+                */
+            } catch (NullPointerException | ClassCastException e) {
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hashCode = (name.hashCode() << 3) ^ locale.hashCode();
+            ClassLoader loader = getLoader();
+            if (loader != null) {
+                hashCode ^= loader.hashCode();
+            }
+            return hashCode;
+        }
+
+        String getFormat() {
+            return format;
+        }
+
+        void setFormat(String format) {
+            this.format = format;
+        }
+
+        private void setCause(Throwable cause) {
+            if (this.cause == null) {
+                this.cause = cause;
+            } else {
+                // Override the cause if the previous one is
+                // ClassNotFoundException.
+                if (this.cause instanceof ClassNotFoundException) {
+                    this.cause = cause;
+                }
+            }
+        }
+
+        private Throwable getCause() {
+            return cause;
+        }
+
+        @Override
+        public String toString() {
+            String l = locale.toString();
+            if (l.isEmpty()) {
+                if (!locale.getVariant().isEmpty()) {
+                    l = "__" + locale.getVariant();
+                } else {
+                    l = "\"\"";
+                }
+            }
+            return "CacheKey[" + name +
+                   ", locale=" + l +
+                   ", classLoader" + getLoader() +
+                   // Android-removed: modules are not supported.
+                   // ", module=" + getModule() +
+                   // ", callerModule=" + getCallerModule() +
+                   ", format=" + format +
+                   "]";
+        }
+    }
+
+    /**
+     * The common interface to get a CacheKey in LoaderReference and
+     * BundleReference.
+     */
+    private static interface CacheKeyReference {
+        public CacheKey getCacheKey();
+    }
+
+    /**
+     * References to a CacheKey element as a WeakReference so that it can be
+     * garbage collected when nobody else is using it.
+     */
+    private static class KeyElementReference<T> extends WeakReference<T>
+                                                implements CacheKeyReference {
+        private final CacheKey cacheKey;
+
+        KeyElementReference(T referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        @Override
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * References to bundles are soft references so that they can be garbage
+     * collected when they have no hard references.
+     */
+    private static class BundleReference extends SoftReference<ResourceBundle>
+                                         implements CacheKeyReference {
+        private final CacheKey cacheKey;
+
+        BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        @Override
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name, the default locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @exception java.lang.NullPointerException
+     *     if <code>baseName</code> is <code>null</code>
+     * @exception MissingResourceException
+     *     if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and the default locale
+     *
+     * @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName)
+    {
+        Class<?> caller = Reflection.getCallerClass();
+        return getBundleImpl(baseName, Locale.getDefault(),
+                             caller, getDefaultControl(caller, baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, the
+     * default locale and the specified control. Calling this method
+     * is equivalent to calling
+     * <pre>
+     * getBundle(baseName, Locale.getDefault(),
+     *           this.getClass().getClassLoader(), control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class
+     *        name
+     * @param control
+     *        the control which gives information for the resource bundle
+     *        loading process
+     * @return a resource bundle for the given base name and the default locale
+     * @throws NullPointerException
+     *         if <code>baseName</code> or <code>control</code> is
+     *         <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @since 1.6
+     * @revised 9
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Control control) {
+        Class<?> caller = Reflection.getCallerClass();
+        Locale targetLocale = Locale.getDefault();
+        // Android-removed: modules are not supported.
+        // checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, control);
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name and locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class name
+     * @param locale
+     *        the locale for which a resource bundle is desired
+     * @exception NullPointerException
+     *        if <code>baseName</code> or <code>locale</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and locale
+     *
+     * @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Locale locale)
+    {
+        Class<?> caller = Reflection.getCallerClass();
+        return getBundleImpl(baseName, locale,
+                             caller, getDefaultControl(caller, baseName));
+    }
+
+    // Android-removed: modules are not supported.
+    /*
+     * Gets a resource bundle using the specified base name and the default locale
+     * on behalf of the specified module. This method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, Locale.getDefault(), module)</code>
+     * </blockquote>
+     *
+     * @param baseName the base name of the resource bundle,
+     *                 a fully qualified class name
+     * @param module   the module for which the resource bundle is searched
+     * @throws NullPointerException
+     *         if {@code baseName} or {@code module} is {@code null}
+     * @throws SecurityException
+     *         if a security manager exists and the caller is not the specified
+     *         module and doesn't have {@code RuntimePermission("getClassLoader")}
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found in the
+     *         specified module
+     * @return a resource bundle for the given base name and the default locale
+     * @since 9
+     * @spec JPMS
+     * @see ResourceBundleProvider
+     * @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
+     * @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
+     *
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Module module) {
+        return getBundleFromModule(Reflection.getCallerClass(), module, baseName,
+                                   Locale.getDefault(),
+                                   getDefaultControl(module, baseName));
+    }
+
+    /*
+     * Gets a resource bundle using the specified base name and locale
+     * on behalf of the specified module.
+     *
+     * <p> Resource bundles in named modules may be encapsulated.  When
+     * the resource bundle is loaded from a
+     * {@linkplain ResourceBundleProvider service provider}, the caller module
+     * must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
+     * to declare that the module uses of {@link ResourceBundleProvider}
+     * for the named resource bundle.
+     * Otherwise, it will load the resource bundles that are local in the
+     * given module as if calling {@link Module#getResourceAsStream(String)}
+     * or that are visible to the class loader of the given module
+     * as if calling {@link ClassLoader#getResourceAsStream(String)}.
+     * When the resource bundle is loaded from the specified module, it is
+     * subject to the encapsulation rules specified by
+     * {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     *
+     * <p>
+     * If the given {@code module} is an unnamed module, then this method is
+     * equivalent to calling {@link #getBundle(String, Locale, ClassLoader)
+     * getBundle(baseName, targetLocale, module.getClassLoader()} to load
+     * resource bundles that are visible to the class loader of the given
+     * unnamed module. Custom {@link java.util.spi.ResourceBundleControlProvider}
+     * implementations, if present, will only be invoked if the specified
+     * module is an unnamed module.
+     *
+     * @param baseName the base name of the resource bundle,
+     *                 a fully qualified class name
+     * @param targetLocale the locale for which a resource bundle is desired
+     * @param module   the module for which the resource bundle is searched
+     * @throws NullPointerException
+     *         if {@code baseName}, {@code targetLocale}, or {@code module} is
+     *         {@code null}
+     * @throws SecurityException
+     *         if a security manager exists and the caller is not the specified
+     *         module and doesn't have {@code RuntimePermission("getClassLoader")}
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name and locale can
+     *         be found in the specified {@code module}
+     * @return a resource bundle for the given base name and locale in the module
+     * @since 9
+     * @spec JPMS
+     * @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
+     * @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
+     *
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
+        return getBundleFromModule(Reflection.getCallerClass(), module, baseName, targetLocale,
+                                   getDefaultControl(module, baseName));
+    }
+    */
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale and control, and the caller's class loader. Calling this
+     * method is equivalent to calling
+     * <pre>
+     * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
+     *           control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and a
+     *         <code>Locale</code> in <code>locales</code>
+     * @throws NullPointerException
+     *         if <code>baseName</code>, <code>locales</code> or
+     *         <code>control</code> is <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name in any
+     *         of the <code>locales</code> can be found.
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @since 1.6
+     * @revised 9
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                                 Control control) {
+        Class<?> caller = Reflection.getCallerClass();
+        // Android-removed: modules are not supported.
+        // checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, control);
+    }
+
+    // Android-removed: Support for ResourceBundleControlProvider.
+    // Removed documentation referring to that SPI.
+    /**
+     * Gets a resource bundle using the specified base name, locale, and class
+     * loader.
+     *
+     * This is equivalent to calling:
+     * <blockquote><pre>
+     * getBundle(baseName, targetLocale, loader, control)
+     * </pre></blockquote>
+     * passing a default instance of {@link Control}.
+     * Refer to the
+     * description of <a href="#modify_default_behavior">modifying the default
+     * behavior</a>. The following describes the default behavior.
+     *
+     * <p>
+     * <b><a id="default_behavior">Resource Bundle Search and Loading Strategy</a></b>
+     *
+     * <p><code>getBundle</code> uses the base name, the specified locale, and
+     * the default locale (obtained from {@link java.util.Locale#getDefault()
+     * Locale.getDefault}) to generate a sequence of <a
+     * id="candidates"><em>candidate bundle names</em></a>.  If the specified
+     * locale's language, script, country, and variant are all empty strings,
+     * then the base name is the only candidate bundle name.  Otherwise, a list
+     * of candidate locales is generated from the attribute values of the
+     * specified locale (language, script, country and variant) and appended to
+     * the base name.  Typically, this will look like the following:
+     *
+     * <pre>
+     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + script + "_" + country
+     *     baseName + "_" + language + "_" + script
+     *     baseName + "_" + language + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + country
+     *     baseName + "_" + language
+     * </pre>
+     *
+     * <p>Candidate bundle names where the final component is an empty string
+     * are omitted, along with the underscore.  For example, if country is an
+     * empty string, the second and the fifth candidate bundle names above
+     * would be omitted.  Also, if script is an empty string, the candidate names
+     * including script are omitted.  For example, a locale with language "de"
+     * and variant "JAVA" will produce candidate names with base name
+     * "MyResource" below.
+     *
+     * <pre>
+     *     MyResource_de__JAVA
+     *     MyResource_de
+     * </pre>
+     *
+     * In the case that the variant contains one or more underscores ('_'), a
+     * sequence of bundle names generated by truncating the last underscore and
+     * the part following it is inserted after a candidate bundle name with the
+     * original variant.  For example, for a locale with language "en", script
+     * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
+     * "MyResource", the list of candidate bundle names below is generated:
+     *
+     * <pre>
+     * MyResource_en_Latn_US_WINDOWS_VISTA
+     * MyResource_en_Latn_US_WINDOWS
+     * MyResource_en_Latn_US
+     * MyResource_en_Latn
+     * MyResource_en_US_WINDOWS_VISTA
+     * MyResource_en_US_WINDOWS
+     * MyResource_en_US
+     * MyResource_en
+     * </pre>
+     *
+     * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
+     * candidate bundle names contains extra names, or the order of bundle names
+     * is slightly modified.  See the description of the default implementation
+     * of {@link Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} for details.</blockquote>
+     *
+     * <p><code>getBundle</code> then iterates over the candidate bundle names
+     * to find the first one for which it can <em>instantiate</em> an actual
+     * resource bundle. It uses the default controls' {@link Control#getFormats
+     * getFormats} method, which generates two bundle names for each generated
+     * name, the first a class name and the second a properties file name. For
+     * each candidate bundle name, it attempts to create a resource bundle:
+     *
+     * <ul><li>First, it attempts to load a class using the generated class name.
+     * If such a class can be found and loaded using the specified class
+     * loader, is assignment compatible with ResourceBundle, is accessible from
+     * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
+     * new instance of this class and uses it as the <em>result resource
+     * bundle</em>.
+     *
+     * <li>Otherwise, <code>getBundle</code> attempts to locate a property
+     * resource file using the generated properties file name.  It generates a
+     * path name from the candidate bundle name by replacing all "." characters
+     * with "/" and appending the string ".properties".  It attempts to find a
+     * "resource" with this name using {@link
+     * java.lang.ClassLoader#getResource(java.lang.String)
+     * ClassLoader.getResource}.  (Note that a "resource" in the sense of
+     * <code>getResource</code> has nothing to do with the contents of a
+     * resource bundle, it is just a container of data, such as a file.)  If it
+     * finds a "resource", it attempts to create a new {@link
+     * PropertyResourceBundle} instance from its contents.  If successful, this
+     * instance becomes the <em>result resource bundle</em>.  </ul>
+     *
+     * <p>This continues until a result resource bundle is instantiated or the
+     * list of candidate bundle names is exhausted.  If no matching resource
+     * bundle is found, the default control's {@link Control#getFallbackLocale
+     * getFallbackLocale} method is called, which returns the current default
+     * locale.  A new sequence of candidate locale names is generated using this
+     * locale and searched again, as above.
+     *
+     * <p>If still no result bundle is found, the base name alone is looked up. If
+     * this still fails, a <code>MissingResourceException</code> is thrown.
+     *
+     * <p><a id="parent_chain"> Once a result resource bundle has been found,
+     * its <em>parent chain</em> is instantiated</a>.  If the result bundle already
+     * has a parent (perhaps because it was returned from a cache) the chain is
+     * complete.
+     *
+     * <p>Otherwise, <code>getBundle</code> examines the remainder of the
+     * candidate locale list that was used during the pass that generated the
+     * result resource bundle.  (As before, candidate bundle names where the
+     * final component is an empty string are omitted.)  When it comes to the
+     * end of the candidate list, it tries the plain bundle name.  With each of the
+     * candidate bundle names it attempts to instantiate a resource bundle (first
+     * looking for a class and then a properties file, as described above).
+     *
+     * <p>Whenever it succeeds, it calls the previously instantiated resource
+     * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
+     * with the new resource bundle.  This continues until the list of names
+     * is exhausted or the current bundle already has a non-null parent.
+     *
+     * <p>Once the parent chain is complete, the bundle is returned.
+     *
+     * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
+     * bundles and might return the same resource bundle instance multiple times.
+     *
+     * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
+     * qualified class name. However, for compatibility with earlier versions,
+     * Java SE Runtime Environments do not verify this, and so it is
+     * possible to access <code>PropertyResourceBundle</code>s by specifying a
+     * path name (using "/") instead of a fully qualified class name (using
+     * ".").
+     *
+     * <p><a id="default_behavior_example">
+     * <strong>Example:</strong></a>
+     * <p>
+     * The following class and property files are provided:
+     * <ul>
+     *     <li>MyResources.class
+     *     <li>MyResources.properties
+     *     <li>MyResources_fr.properties
+     *     <li>MyResources_fr_CH.class
+     *     <li>MyResources_fr_CH.properties
+     *     <li>MyResources_en.properties
+     *     <li>MyResources_es_ES.class
+     * </ul>
+     *
+     * The contents of all files are valid (that is, public non-abstract
+     * subclasses of <code>ResourceBundle</code> for the ".class" files,
+     * syntactically correct ".properties" files).  The default locale is
+     * <code>Locale("en", "GB")</code>.
+     *
+     * <p>Calling <code>getBundle</code> with the locale arguments below will
+     * instantiate resource bundles as follows:
+     *
+     * <table class="striped">
+     * <caption style="display:none">getBundle() locale to resource bundle mapping</caption>
+     * <thead>
+     * <tr><th scope="col">Locale</th><th scope="col">Resource bundle</th></tr>
+     * </thead>
+     * <tbody>
+     * <tr><th scope="row">Locale("fr", "CH")</th><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><th scope="row">Locale("fr", "FR")</th><td>MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><th scope="row">Locale("de", "DE")</th><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><th scope="row">Locale("en", "US")</th><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><th scope="row">Locale("es", "ES")</th><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>The file MyResources_fr_CH.properties is never used because it is
+     * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
+     * is also hidden by MyResources.class.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @param locale the locale for which a resource bundle is desired
+     * @param loader the class loader from which to load the resource bundle
+     * @return a resource bundle for the given base name and locale
+     * @exception java.lang.NullPointerException
+     *        if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @since 1.2
+     * @revised 9
+     */
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Locale locale,
+                                           ClassLoader loader)
+    {
+        if (loader == null) {
+            throw new NullPointerException();
+        }
+        Class<?> caller = Reflection.getCallerClass();
+        return getBundleImpl(baseName, locale, caller, loader, getDefaultControl(caller, baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale, class loader and control. Unlike the {@link
+     * #getBundle(String, Locale, ClassLoader) getBundle}
+     * factory methods with no {@code control} argument, the given
+     * <code>control</code> specifies how to locate and instantiate resource
+     * bundles. Conceptually, the bundle loading process with the given
+     * <code>control</code> is performed in the following steps.
+     *
+     * <ol>
+     * <li>This factory method looks up the resource bundle in the cache for
+     * the specified <code>baseName</code>, <code>targetLocale</code> and
+     * <code>loader</code>.  If the requested resource bundle instance is
+     * found in the cache and the time-to-live periods of the instance and
+     * all of its parent instances have not expired, the instance is returned
+     * to the caller. Otherwise, this factory method proceeds with the
+     * loading process below.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFormats(String)
+     * control.getFormats} method is called to get resource bundle formats
+     * to produce bundle or resource names. The strings
+     * <code>"java.class"</code> and <code>"java.properties"</code>
+     * designate class-based and {@linkplain PropertyResourceBundle
+     * property}-based resource bundles, respectively. Other strings
+     * starting with <code>"java."</code> are reserved for future extensions
+     * and must not be used for application-defined formats. Other strings
+     * designate application-defined formats.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
+     * Locale) control.getCandidateLocales} method is called with the target
+     * locale to get a list of <em>candidate <code>Locale</code>s</em> for
+     * which resource bundles are searched.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
+     * String, ClassLoader, boolean) control.newBundle} method is called to
+     * instantiate a <code>ResourceBundle</code> for the base bundle name, a
+     * candidate locale, and a format. (Refer to the note on the cache
+     * lookup below.) This step is iterated over all combinations of the
+     * candidate locales and formats until the <code>newBundle</code> method
+     * returns a <code>ResourceBundle</code> instance or the iteration has
+     * used up all the combinations. For example, if the candidate locales
+     * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
+     * <code>Locale("")</code> and the formats are <code>"java.class"</code>
+     * and <code>"java.properties"</code>, then the following is the
+     * sequence of locale-format combinations to be used to call
+     * <code>control.newBundle</code>.
+     *
+     * <table class=striped style="width: 50%; text-align: left; margin-left: 40px;">
+     * <caption style="display:none">locale-format combinations for newBundle</caption>
+     * <thead>
+     * <tr>
+     * <th scope="col">Index</th>
+     * <th scope="col"><code>Locale</code></th>
+     * <th scope="col"><code>format</code></th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row">1</th>
+     * <td><code>Locale("de", "DE")</code></td>
+     * <td><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">2</th>
+     * <td><code>Locale("de", "DE")</code></td>
+     * <td><code>java.properties</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">3</th>
+     * <td><code>Locale("de")</code></td>
+     * <td><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">4</th>
+     * <td><code>Locale("de")</code></td>
+     * <td><code>java.properties</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">5</th>
+     * <td><code>Locale("")</code></td>
+     * <td><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <th scope="row">6</th>
+     * <td><code>Locale("")</code></td>
+     * <td><code>java.properties</code></td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </li>
+     *
+     * <li>If the previous step has found no resource bundle, proceed to
+     * Step 6. If a bundle has been found that is a base bundle (a bundle
+     * for <code>Locale("")</code>), and the candidate locale list only contained
+     * <code>Locale("")</code>, return the bundle to the caller. If a bundle
+     * has been found that is a base bundle, but the candidate locale list
+     * contained locales other than Locale(""), put the bundle on hold and
+     * proceed to Step 6. If a bundle has been found that is not a base
+     * bundle, proceed to Step 7.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
+     * Locale) control.getFallbackLocale} method is called to get a fallback
+     * locale (alternative to the current target locale) to try further
+     * finding a resource bundle. If the method returns a non-null locale,
+     * it becomes the next target locale and the loading process starts over
+     * from Step 3. Otherwise, if a base bundle was found and put on hold in
+     * a previous Step 5, it is returned to the caller now. Otherwise, a
+     * MissingResourceException is thrown.</li>
+     *
+     * <li>At this point, we have found a resource bundle that's not the
+     * base bundle. If this bundle set its parent during its instantiation,
+     * it is returned to the caller. Otherwise, its <a
+     * href="./ResourceBundle.html#parent_chain">parent chain</a> is
+     * instantiated based on the list of candidate locales from which it was
+     * found. Finally, the bundle is returned to the caller.</li>
+     * </ol>
+     *
+     * <p>During the resource bundle loading process above, this factory
+     * method looks up the cache before calling the {@link
+     * Control#newBundle(String, Locale, String, ClassLoader, boolean)
+     * control.newBundle} method.  If the time-to-live period of the
+     * resource bundle found in the cache has expired, the factory method
+     * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
+     * String, ClassLoader, ResourceBundle, long) control.needsReload}
+     * method to determine whether the resource bundle needs to be reloaded.
+     * If reloading is required, the factory method calls
+     * <code>control.newBundle</code> to reload the resource bundle.  If
+     * <code>control.newBundle</code> returns <code>null</code>, the factory
+     * method puts a dummy resource bundle in the cache as a mark of
+     * nonexistent resource bundles in order to avoid lookup overhead for
+     * subsequent requests. Such dummy resource bundles are under the same
+     * expiration control as specified by <code>control</code>.
+     *
+     * <p>All resource bundles loaded are cached by default. Refer to
+     * {@link Control#getTimeToLive(String,Locale)
+     * control.getTimeToLive} for details.
+     *
+     * <p>The following is an example of the bundle loading process with the
+     * default <code>ResourceBundle.Control</code> implementation.
+     *
+     * <p>Conditions:
+     * <ul>
+     * <li>Base bundle name: <code>foo.bar.Messages</code>
+     * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
+     * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
+     * <li>Available resource bundles:
+     * <code>foo/bar/Messages_fr.properties</code> and
+     * <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>First, <code>getBundle</code> tries loading a resource bundle in
+     * the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_it_IT</code>
+     * <li>file <code>foo/bar/Messages_it_IT.properties</code>
+     * <li>class <code>foo.bar.Messages_it</code></li>
+     * <li>file <code>foo/bar/Messages_it.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>At this point, <code>getBundle</code> finds
+     * <code>foo/bar/Messages.properties</code>, which is put on hold
+     * because it's the base bundle.  <code>getBundle</code> calls {@link
+     * Control#getFallbackLocale(String, Locale)
+     * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
+     * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
+     * tries loading a bundle in the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_fr</code></li>
+     * <li>file <code>foo/bar/Messages_fr.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p><code>getBundle</code> finds
+     * <code>foo/bar/Messages_fr.properties</code> and creates a
+     * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
+     * sets up its parent chain from the list of the candidate locales.  Only
+     * <code>foo/bar/Messages.properties</code> is found in the list and
+     * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
+     * that becomes the parent of the instance for
+     * <code>foo/bar/Messages_fr.properties</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param loader
+     *        the class loader from which to load the resource bundle
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and locale
+     * @throws NullPointerException
+     *         if <code>baseName</code>, <code>targetLocale</code>,
+     *         <code>loader</code>, or <code>control</code> is
+     *         <code>null</code>
+     * @throws MissingResourceException
+     *         if no resource bundle for the specified base name can be found
+     * @throws IllegalArgumentException
+     *         if the given <code>control</code> doesn't perform properly
+     *         (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *         Note that validation of <code>control</code> is performed as
+     *         needed.
+     * @since 1.6
+     * @revised 9
+     */
+    @CallerSensitive
+    public static ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                           ClassLoader loader, Control control) {
+        if (loader == null || control == null) {
+            throw new NullPointerException();
+        }
+        Class<?> caller = Reflection.getCallerClass();
+        // Android-removed: modules are not supported.
+        // checkNamedModule(caller);
+        return getBundleImpl(baseName, targetLocale, caller, loader, control);
+    }
+
+    private static Control getDefaultControl(String baseName) {
+        // Android-removed: Support for ResourceBundleControlProvider.
+        /*
+        if (providers != null) {
+            for (ResourceBundleControlProvider provider : providers) {
+                Control control = provider.getControl(baseName);
+                if (control != null) {
+                    return control;
+                }
+            }
+        }
+        */
+        return Control.INSTANCE;
+    }
+
+    private static Control getDefaultControl(Class<?> caller, String baseName) {
+        // Android-removed: modules are not supported.
+        // return getDefaultControl(caller.getModule(), baseName);
+        return getDefaultControl(baseName);
+    }
+
+    // Android-removed: modules are not supported
+    /*
+    private static Control getDefaultControl(Module targetModule, String baseName) {
+        return targetModule.isNamed() ?
+            Control.INSTANCE :
+            ResourceBundleControlProviderHolder.getControl(baseName);
+    }
+    */
+
+    // Android-removed: support for ResourceBundleControlProvider
+    /*
+    private static class ResourceBundleControlProviderHolder {
+        private static final PrivilegedAction<List<ResourceBundleControlProvider>> pa =
+            () -> {
+                return Collections.unmodifiableList(
+                    ServiceLoader.load(ResourceBundleControlProvider.class,
+                                       ClassLoader.getSystemClassLoader()).stream()
+                        .map(ServiceLoader.Provider::get)
+                        .collect(Collectors.toList()));
+            };
+
+        private static final List<ResourceBundleControlProvider> CONTROL_PROVIDERS =
+            AccessController.doPrivileged(pa);
+
+        private static Control getControl(String baseName) {
+            return CONTROL_PROVIDERS.isEmpty() ?
+                Control.INSTANCE :
+                CONTROL_PROVIDERS.stream()
+                    .flatMap(provider -> Stream.ofNullable(provider.getControl(baseName)))
+                    .findFirst()
+                    .orElse(Control.INSTANCE);
+        }
+    }
+    */
+
+    // Android-removed: modules are not supported
+    /*
+    private static void checkNamedModule(Class<?> caller) {
+        if (caller.getModule().isNamed()) {
+            throw new UnsupportedOperationException(
+                    "ResourceBundle.Control not supported in named modules");
+        }
+    }
+    */
+
+    private static ResourceBundle getBundleImpl(String baseName,
+                                                Locale locale,
+                                                Class<?> caller,
+                                                Control control) {
+        return getBundleImpl(baseName, locale, caller, caller.getClassLoader(), control);
+    }
+
+    /**
+     * This method will find resource bundles using the legacy mechanism
+     * if the caller is unnamed module or the given class loader is
+     * not the class loader of the caller module getting the resource
+     * bundle, i.e. find the class that is visible to the class loader
+     * and properties from unnamed module.
+     *
+     * The module-aware resource bundle lookup mechanism will load
+     * the service providers using the service loader mechanism
+     * as well as properties local in the caller module.
+     */
+    private static ResourceBundle getBundleImpl(String baseName,
+                                                Locale locale,
+                                                Class<?> caller,
+                                                ClassLoader loader,
+                                                Control control) {
+        if (caller == null) {
+            throw new InternalError("null caller");
+        }
+
+        // Android-removed: modules are not supported.
+        /*
+        Module callerModule = caller.getModule();
+
+        // get resource bundles for a named module only if loader is the module's class loader
+        if (callerModule.isNamed() && loader == getLoader(callerModule)) {
+            return getBundleImpl(callerModule, callerModule, baseName, locale, control);
+        }
+
+        // find resource bundles from unnamed module of given class loader
+        // Java agent can add to the bootclasspath e.g. via
+        // java.lang.instrument.Instrumentation and load classes in unnamed module.
+        // It may call RB::getBundle that will end up here with loader == null.
+        Module unnamedModule = loader != null
+            ? loader.getUnnamedModule()
+            : BootLoader.getUnnamedModule();
+        */
+        // return getBundleImpl(callerModule, unnamedModule, baseName, locale, control);
+        return getBundleImpl(baseName, locale, loader, control);
+    }
+
+    // Android-removed: modules are not supported.
+    /*
+    private static ResourceBundle getBundleFromModule(Class<?> caller,
+                                                      Module module,
+                                                      String baseName,
+                                                      Locale locale,
+                                                      Control control) {
+        Objects.requireNonNull(module);
+        Module callerModule = caller.getModule();
+        if (callerModule != module) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(GET_CLASSLOADER_PERMISSION);
+            }
+        }
+        return getBundleImpl(callerModule, module, baseName, locale, control);
+    }
+    */
+
+    // Android-changed: modules are not supported.
+    // private static ResourceBundle getBundleImpl(Module callerModule,
+    //                                          Module module,
+    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
+                                                ClassLoader loader, Control control) {
+        if (locale == null || control == null) {
+            throw new NullPointerException();
+        }
+
+        // We create a CacheKey here for use by this call. The base name
+        // and modules will never change during the bundle loading
+        // process. We have to make sure that the locale is set before
+        // using it as a cache key.
+        // CacheKey cacheKey = new CacheKey(baseName, locale, module, callerModule);
+        CacheKey cacheKey = new CacheKey(baseName, locale, loader);
+        ResourceBundle bundle = null;
+
+        // Quick lookup of the cache.
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef != null) {
+            bundle = bundleRef.get();
+            bundleRef = null;
+        }
+
+        // If this bundle and all of its parents are valid (not expired),
+        // then return this bundle. If any of the bundles is expired, we
+        // don't call control.needsReload here but instead drop into the
+        // complete loading process below.
+        if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
+            return bundle;
+        }
+
+        // No valid bundle was found in the cache, so we need to load the
+        // resource bundle and its parents.
+
+        boolean isKnownControl = (control == Control.INSTANCE) ||
+                                   (control instanceof SingleFormatControl);
+        List<String> formats = control.getFormats(baseName);
+        if (!isKnownControl && !checkList(formats)) {
+            throw new IllegalArgumentException("Invalid Control: getFormats");
+        }
+
+        ResourceBundle baseBundle = null;
+        for (Locale targetLocale = locale;
+             targetLocale != null;
+             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
+            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
+            if (!isKnownControl && !checkList(candidateLocales)) {
+                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
+            }
+            /*
+            bundle = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, 0, control, baseBundle);
+            */
+            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
+
+            // If the loaded bundle is the base bundle and exactly for the
+            // requested locale or the only candidate locale, then take the
+            // bundle as the resulting one. If the loaded bundle is the base
+            // bundle, it's put on hold until we finish processing all
+            // fallback locales.
+            if (isValidBundle(bundle)) {
+                boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
+                if (!isBaseBundle || bundle.locale.equals(locale)
+                    || (candidateLocales.size() == 1
+                        && bundle.locale.equals(candidateLocales.get(0)))) {
+                    break;
+                }
+
+                // If the base bundle has been loaded, keep the reference in
+                // baseBundle so that we can avoid any redundant loading in case
+                // the control specify not to cache bundles.
+                if (isBaseBundle && baseBundle == null) {
+                    baseBundle = bundle;
+                }
+            }
+        }
+
+        if (bundle == null) {
+            if (baseBundle == null) {
+                throwMissingResourceException(baseName, locale, cacheKey.getCause());
+            }
+            bundle = baseBundle;
+        }
+
+        // keep callerModule and module reachable for as long as we are operating
+        // with WeakReference(s) to them (in CacheKey)...
+        // Reference.reachabilityFence(callerModule);
+        // Reference.reachabilityFence(module);
+
+        return bundle;
+    }
+
+    /**
+     * Checks if the given <code>List</code> is not null, not empty,
+     * not having null in its elements.
+     */
+    private static boolean checkList(List<?> a) {
+        boolean valid = (a != null && !a.isEmpty());
+        if (valid) {
+            int size = a.size();
+            for (int i = 0; valid && i < size; i++) {
+                valid = (a.get(i) != null);
+            }
+        }
+        return valid;
+    }
+
+    // private static ResourceBundle findBundle(Module callerModule,
+    //                                         Module module,
+    private static ResourceBundle findBundle(CacheKey cacheKey,
+                                             List<Locale> candidateLocales,
+                                             List<String> formats,
+                                             int index,
+                                             Control control,
+                                             ResourceBundle baseBundle) {
+        Locale targetLocale = candidateLocales.get(index);
+        ResourceBundle parent = null;
+        if (index != candidateLocales.size() - 1) {
+            /*
+            parent = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, index + 1,
+                                control, baseBundle);
+            */
+            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
+                                control, baseBundle);
+        } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
+            return baseBundle;
+        }
+
+        // Before we do the real loading work, see whether we need to
+        // do some housekeeping: If references to modules or
+        // resource bundles have been nulled out, remove all related
+        // information from the cache.
+        Object ref;
+        while ((ref = referenceQueue.poll()) != null) {
+            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
+        }
+
+        // flag indicating the resource bundle has expired in the cache
+        boolean expiredBundle = false;
+
+        // First, look up the cache to see if it's in the cache, without
+        // attempting to load bundle.
+        cacheKey.setLocale(targetLocale);
+        ResourceBundle bundle = findBundleInCache(cacheKey, control);
+        if (isValidBundle(bundle)) {
+            expiredBundle = bundle.expired;
+            if (!expiredBundle) {
+                // If its parent is the one asked for by the candidate
+                // locales (the runtime lookup path), we can take the cached
+                // one. (If it's not identical, then we'd have to check the
+                // parent's parents to be consistent with what's been
+                // requested.)
+                if (bundle.parent == parent) {
+                    return bundle;
+                }
+                // Otherwise, remove the cached one since we can't keep
+                // the same bundles having different parents.
+                BundleReference bundleRef = cacheList.get(cacheKey);
+                // Android-changed: Use refersTo().
+                if (bundleRef != null && bundleRef.refersTo(bundle)) {
+                    cacheList.remove(cacheKey, bundleRef);
+                }
+            }
+        }
+
+        if (bundle != NONEXISTENT_BUNDLE) {
+            trace("findBundle: %d %s %s formats: %s%n", index, candidateLocales, cacheKey, formats);
+            /*
+            if (module.isNamed()) {
+                bundle = loadBundle(cacheKey, formats, control, module, callerModule);
+            } else {
+                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+            }
+            */
+            bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+            if (bundle != null) {
+                if (bundle.parent == null) {
+                    bundle.setParent(parent);
+                }
+                bundle.locale = targetLocale;
+                bundle = putBundleInCache(cacheKey, bundle, control);
+                return bundle;
+            }
+
+            // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+            // instance for the locale.
+            putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
+        }
+        return parent;
+    }
+
+    private static final String UNKNOWN_FORMAT = "";
+
+
+    // Android-removed: modules are not supported.
+    /*
+     * Loads a ResourceBundle in named modules
+     *
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             Module module,
+                                             Module callerModule) {
+        String baseName = cacheKey.getName();
+        Locale targetLocale = cacheKey.getLocale();
+
+        ResourceBundle bundle = null;
+        if (cacheKey.hasProviders()) {
+            if (callerModule == module) {
+                bundle = loadBundleFromProviders(baseName,
+                                                 targetLocale,
+                                                 cacheKey.getProviders(),
+                                                 cacheKey);
+            } else {
+                // load from provider if the caller module has access to the
+                // service type and also declares `uses`
+                ClassLoader loader = getLoader(module);
+                Class<ResourceBundleProvider> svc =
+                    getResourceBundleProviderType(baseName, loader);
+                if (svc != null
+                        && Reflection.verifyModuleAccess(callerModule, svc)
+                        && callerModule.canUse(svc)) {
+                    bundle = loadBundleFromProviders(baseName,
+                                                     targetLocale,
+                                                     cacheKey.getProviders(),
+                                                     cacheKey);
+                }
+            }
+
+            if (bundle != null) {
+                cacheKey.setFormat(UNKNOWN_FORMAT);
+            }
+        }
+
+        // If none of providers returned a bundle and the caller has no provider,
+        // look up module-local bundles or from the class path
+        if (bundle == null && !cacheKey.callerHasProvider()) {
+            for (String format : formats) {
+                try {
+                    switch (format) {
+                    case "java.class":
+                        bundle = ResourceBundleProviderHelper
+                            .loadResourceBundle(callerModule, module, baseName, targetLocale);
+
+                        break;
+                    case "java.properties":
+                        bundle = ResourceBundleProviderHelper
+                            .loadPropertyResourceBundle(callerModule, module, baseName, targetLocale);
+                        break;
+                    default:
+                        throw new InternalError("unexpected format: " + format);
+                    }
+
+                    if (bundle != null) {
+                        cacheKey.setFormat(format);
+                        break;
+                    }
+                } catch (LinkageError|Exception e) {
+                    cacheKey.setCause(e);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    /*
+     * Returns a ServiceLoader that will find providers that are bound to
+     * a given named module.
+     *
+    private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
+                                                                          String baseName)
+    {
+        if (!module.isNamed()) {
+            return null;
+        }
+
+        ClassLoader loader = getLoader(module);
+        Class<ResourceBundleProvider> service =
+                getResourceBundleProviderType(baseName, loader);
+        if (service != null && Reflection.verifyModuleAccess(module, service)) {
+            try {
+                // locate providers that are visible to the class loader
+                // ServiceConfigurationError will be thrown if the module
+                // does not declare `uses` the service type
+                return ServiceLoader.load(service, loader, module);
+            } catch (ServiceConfigurationError e) {
+                // "uses" not declared
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the service type of the given baseName that is visible
+     * to the given class loader
+     *
+    private static Class<ResourceBundleProvider>
+            getResourceBundleProviderType(String baseName, ClassLoader loader)
+    {
+        // Look up <packagename> + ".spi." + <name>"Provider"
+        int i = baseName.lastIndexOf('.');
+        if (i <= 0) {
+            return null;
+        }
+
+        String name = baseName.substring(i+1, baseName.length()) + "Provider";
+        String providerName = baseName.substring(0, i) + ".spi." + name;
+
+        // Use the class loader of the getBundle caller so that the caller's
+        // visibility of the provider type is checked.
+        return AccessController.doPrivileged(
+            new PrivilegedAction<>() {
+                @Override
+                public Class<ResourceBundleProvider> run() {
+                    try {
+                        Class<?> c = Class.forName(providerName, false, loader);
+                        if (ResourceBundleProvider.class.isAssignableFrom(c)) {
+                            @SuppressWarnings("unchecked")
+                            Class<ResourceBundleProvider> s = (Class<ResourceBundleProvider>) c;
+                            return s;
+                        }
+                    } catch (ClassNotFoundException e) {}
+                    return null;
+                }
+            });
+    }
+
+    /**
+     * Loads ResourceBundle from service providers.
+     *
+    private static ResourceBundle loadBundleFromProviders(String baseName,
+                                                          Locale locale,
+                                                          ServiceLoader<ResourceBundleProvider> providers,
+                                                          CacheKey cacheKey)
+    {
+        if (providers == null) return null;
+
+        return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    public ResourceBundle run() {
+                        for (Iterator<ResourceBundleProvider> itr = providers.iterator(); itr.hasNext(); ) {
+                            try {
+                                ResourceBundleProvider provider = itr.next();
+                                if (cacheKey != null && cacheKey.callerHasProvider == null
+                                        && cacheKey.getModule() == provider.getClass().getModule()) {
+                                    cacheKey.callerHasProvider = Boolean.TRUE;
+                                }
+                                ResourceBundle bundle = provider.getBundle(baseName, locale);
+                                trace("provider %s %s locale: %s bundle: %s%n", provider, baseName, locale, bundle);
+                                if (bundle != null) {
+                                    return bundle;
+                                }
+                            } catch (ServiceConfigurationError | SecurityException e) {
+                                if (cacheKey != null) {
+                                    cacheKey.setCause(e);
+                                }
+                            }
+                        }
+                        if (cacheKey != null && cacheKey.callerHasProvider == null) {
+                            cacheKey.callerHasProvider = Boolean.FALSE;
+                        }
+                        return null;
+                    }
+                });
+
+    }
+    */
+
+    /*
+     * Legacy mechanism to load resource bundles
+     */
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             boolean reload) {
+
+        // Here we actually load the bundle in the order of formats
+        // specified by the getFormats() value.
+        Locale targetLocale = cacheKey.getLocale();
+
+        // Android-removed: modules are not supported
+        /*
+        Module module = cacheKey.getModule();
+        if (module == null) {
+            // should not happen
+            throw new InternalError(
+                "Module for cache key: " + cacheKey + " has been GCed.");
+        }
+        ClassLoader loader = getLoaderForControl(module);
+        */
+
+        ResourceBundle bundle = null;
+        for (String format : formats) {
+            try {
+                // ResourceBundle.Control.newBundle may be overridden
+                bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
+                                           cacheKey.getLoader(), reload);
+            } catch (LinkageError | Exception error) {
+                // We need to handle the LinkageError case due to
+                // inconsistent case-sensitivity in ClassLoader.
+                // See 6572242 for details.
+                cacheKey.setCause(error);
+            }
+            if (bundle != null) {
+                // Set the format in the cache key so that it can be
+                // used when calling needsReload later.
+                cacheKey.setFormat(format);
+                bundle.name = cacheKey.getName();
+                bundle.locale = targetLocale;
+                // Bundle provider might reuse instances. So we should make
+                // sure to clear the expired flag here.
+                bundle.expired = false;
+                break;
+            }
+        }
+
+        return bundle;
+    }
+
+    private static boolean isValidBundle(ResourceBundle bundle) {
+        return bundle != null && bundle != NONEXISTENT_BUNDLE;
+    }
+
+    /**
+     * Determines whether any of resource bundles in the parent chain,
+     * including the leaf, have expired.
+     */
+    private static boolean hasValidParentChain(ResourceBundle bundle) {
+        long now = System.currentTimeMillis();
+        while (bundle != null) {
+            if (bundle.expired) {
+                return false;
+            }
+            CacheKey key = bundle.cacheKey;
+            if (key != null) {
+                long expirationTime = key.expirationTime;
+                if (expirationTime >= 0 && expirationTime <= now) {
+                    return false;
+                }
+            }
+            bundle = bundle.parent;
+        }
+        return true;
+    }
+
+    /**
+     * Throw a MissingResourceException with proper message
+     */
+    private static void throwMissingResourceException(String baseName,
+                                                      Locale locale,
+                                                      Throwable cause) {
+        // If the cause is a MissingResourceException, avoid creating
+        // a long chain. (6355009)
+        if (cause instanceof MissingResourceException) {
+            cause = null;
+        }
+        throw new MissingResourceException("Can't find bundle for base name "
+                                           + baseName + ", locale " + locale,
+                                           baseName + "_" + locale, // className
+                                           "",                      // key
+                                           cause);
+    }
+
+    /**
+     * Finds a bundle in the cache. Any expired bundles are marked as
+     * `expired' and removed from the cache upon return.
+     *
+     * @param cacheKey the key to look up the cache
+     * @param control the Control to be used for the expiration control
+     * @return the cached bundle, or null if the bundle is not found in the
+     * cache or its parent has expired. <code>bundle.expire</code> is true
+     * upon return if the bundle in the cache has expired.
+     */
+    private static ResourceBundle findBundleInCache(CacheKey cacheKey,
+                                                    Control control) {
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef == null) {
+            return null;
+        }
+        ResourceBundle bundle = bundleRef.get();
+        if (bundle == null) {
+            return null;
+        }
+        ResourceBundle p = bundle.parent;
+        assert p != NONEXISTENT_BUNDLE;
+        // If the parent has expired, then this one must also expire. We
+        // check only the immediate parent because the actual loading is
+        // done from the root (base) to leaf (child) and the purpose of
+        // checking is to propagate expiration towards the leaf. For
+        // example, if the requested locale is ja_JP_JP and there are
+        // bundles for all of the candidates in the cache, we have a list,
+        //
+        // base <- ja <- ja_JP <- ja_JP_JP
+        //
+        // If ja has expired, then it will reload ja and the list becomes a
+        // tree.
+        //
+        // base <- ja (new)
+        //  "   <- ja (expired) <- ja_JP <- ja_JP_JP
+        //
+        // When looking up ja_JP in the cache, it finds ja_JP in the cache
+        // which references to the expired ja. Then, ja_JP is marked as
+        // expired and removed from the cache. This will be propagated to
+        // ja_JP_JP.
+        //
+        // Now, it's possible, for example, that while loading new ja_JP,
+        // someone else has started loading the same bundle and finds the
+        // base bundle has expired. Then, what we get from the first
+        // getBundle call includes the expired base bundle. However, if
+        // someone else didn't start its loading, we wouldn't know if the
+        // base bundle has expired at the end of the loading process. The
+        // expiration control doesn't guarantee that the returned bundle and
+        // its parents haven't expired.
+        //
+        // We could check the entire parent chain to see if there's any in
+        // the chain that has expired. But this process may never end. An
+        // extreme case would be that getTimeToLive returns 0 and
+        // needsReload always returns true.
+        if (p != null && p.expired) {
+            assert bundle != NONEXISTENT_BUNDLE;
+            bundle.expired = true;
+            bundle.cacheKey = null;
+            cacheList.remove(cacheKey, bundleRef);
+            bundle = null;
+        } else {
+            CacheKey key = bundleRef.getCacheKey();
+            long expirationTime = key.expirationTime;
+            if (!bundle.expired && expirationTime >= 0 &&
+                expirationTime <= System.currentTimeMillis()) {
+                // its TTL period has expired.
+                if (bundle != NONEXISTENT_BUNDLE) {
+                    // Synchronize here to call needsReload to avoid
+                    // redundant concurrent calls for the same bundle.
+                    synchronized (bundle) {
+                        expirationTime = key.expirationTime;
+                        if (!bundle.expired && expirationTime >= 0 &&
+                            expirationTime <= System.currentTimeMillis()) {
+                            try {
+                                // Android-changed: modules are not supported.
+                                /*
+                                Module module = cacheKey.getModule();
+                                bundle.expired =
+                                   module == null || // already GCed
+                                */
+                                bundle.expired = control.needsReload(key.getName(),
+                                                        key.getLocale(),
+                                                        key.getFormat(),
+                                                        // getLoaderForControl(module),
+                                                        key.getLoader(),
+                                                        bundle,
+                                                        key.loadTime);
+                            } catch (Exception e) {
+                                cacheKey.setCause(e);
+                            }
+                            if (bundle.expired) {
+                                // If the bundle needs to be reloaded, then
+                                // remove the bundle from the cache, but
+                                // return the bundle with the expired flag
+                                // on.
+                                bundle.cacheKey = null;
+                                cacheList.remove(cacheKey, bundleRef);
+                            } else {
+                                // Update the expiration control info. and reuse
+                                // the same bundle instance
+                                setExpirationTime(key, control);
+                            }
+                        }
+                    }
+                } else {
+                    // We just remove NONEXISTENT_BUNDLE from the cache.
+                    cacheList.remove(cacheKey, bundleRef);
+                    bundle = null;
+                }
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Put a new bundle in the cache.
+     *
+     * @param cacheKey the key for the resource bundle
+     * @param bundle the resource bundle to be put in the cache
+     * @return the ResourceBundle for the cacheKey; if someone has put
+     * the bundle before this call, the one found in the cache is
+     * returned.
+     */
+    private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+                                                   ResourceBundle bundle,
+                                                   Control control) {
+        setExpirationTime(cacheKey, control);
+        if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
+            CacheKey key = new CacheKey(cacheKey);
+            BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
+            bundle.cacheKey = key;
+
+            // Put the bundle in the cache if it's not been in the cache.
+            BundleReference result = cacheList.putIfAbsent(key, bundleRef);
+
+            // If someone else has put the same bundle in the cache before
+            // us and it has not expired, we should use the one in the cache.
+            if (result != null) {
+                ResourceBundle rb = result.get();
+                if (rb != null && !rb.expired) {
+                    // Clear the back link to the cache key
+                    bundle.cacheKey = null;
+                    bundle = rb;
+                    // Clear the reference in the BundleReference so that
+                    // it won't be enqueued.
+                    bundleRef.clear();
+                } else {
+                    // Replace the invalid (garbage collected or expired)
+                    // instance with the valid one.
+                    cacheList.put(key, bundleRef);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    private static void setExpirationTime(CacheKey cacheKey, Control control) {
+        long ttl = control.getTimeToLive(cacheKey.getName(),
+                                         cacheKey.getLocale());
+        if (ttl >= 0) {
+            // If any expiration time is specified, set the time to be
+            // expired in the cache.
+            long now = System.currentTimeMillis();
+            cacheKey.loadTime = now;
+            cacheKey.expirationTime = now + ttl;
+        } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
+            cacheKey.expirationTime = ttl;
+        } else {
+            throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
+        }
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * using the caller's class loader.
+     *
+     * @since 1.6
+     * @revised 9
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    @CallerSensitive
+    public static final void clearCache() {
+        // Android-changed: modules are not supported.
+        /*
+        Class<?> caller = Reflection.getCallerClass();
+        cacheList.keySet().removeIf(
+            key -> key.getCallerModule() == caller.getModule()
+        );
+        */
+        clearCache(getLoader(Reflection.getCallerClass()));
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * by the given class loader.
+     *
+     * @param loader the class loader
+     * @exception NullPointerException if <code>loader</code> is null
+     * @since 1.6
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    public static final void clearCache(ClassLoader loader) {
+        Objects.requireNonNull(loader);
+        // Android-changed: modules are no supported.
+        /*
+        cacheList.keySet().removeIf(
+            key -> {
+                Module m;
+                return (m = key.getModule()) != null &&
+                       getLoader(m) == loader;
+            }
+        );
+        */
+        cacheList.keySet().removeIf(key -> key.getLoader() == loader);
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle.
+     * Returns null if this resource bundle does not contain an
+     * object for the given key.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @return the object for the given key, or null
+     */
+    protected abstract Object handleGetObject(String key);
+
+    /**
+     * Returns an enumeration of the keys.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     */
+    public abstract Enumeration<String> getKeys();
+
+    /**
+     * Determines whether the given <code>key</code> is contained in
+     * this <code>ResourceBundle</code> or its parent bundles.
+     *
+     * @param key
+     *        the resource <code>key</code>
+     * @return <code>true</code> if the given <code>key</code> is
+     *        contained in this <code>ResourceBundle</code> or its
+     *        parent bundles; <code>false</code> otherwise.
+     * @exception NullPointerException
+     *         if <code>key</code> is <code>null</code>
+     * @since 1.6
+     */
+    public boolean containsKey(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            if (rb.handleKeySet().contains(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a <code>Set</code> of all keys contained in this
+     * <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return a <code>Set</code> of all keys contained in this
+     *         <code>ResourceBundle</code> and its parent bundles.
+     * @since 1.6
+     */
+    public Set<String> keySet() {
+        Set<String> keys = new HashSet<>();
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            keys.addAll(rb.handleKeySet());
+        }
+        return keys;
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained <em>only</em>
+     * in this <code>ResourceBundle</code>.
+     *
+     * <p>The default implementation returns a <code>Set</code> of the
+     * keys returned by the {@link #getKeys() getKeys} method except
+     * for the ones for which the {@link #handleGetObject(String)
+     * handleGetObject} method returns <code>null</code>. Once the
+     * <code>Set</code> has been created, the value is kept in this
+     * <code>ResourceBundle</code> in order to avoid producing the
+     * same <code>Set</code> in subsequent calls. Subclasses can
+     * override this method for faster handling.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *        <code>ResourceBundle</code>
+     * @since 1.6
+     */
+    protected Set<String> handleKeySet() {
+        if (keySet == null) {
+            synchronized (this) {
+                if (keySet == null) {
+                    Set<String> keys = new HashSet<>();
+                    Enumeration<String> enumKeys = getKeys();
+                    while (enumKeys.hasMoreElements()) {
+                        String key = enumKeys.nextElement();
+                        if (handleGetObject(key) != null) {
+                            keys.add(key);
+                        }
+                    }
+                    keySet = keys;
+                }
+            }
+        }
+        return keySet;
+    }
+
+
+
+    /**
+     * <code>ResourceBundle.Control</code> defines a set of callback methods
+     * that are invoked by the {@link ResourceBundle#getBundle(String,
+     * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
+     * methods during the bundle loading process. In other words, a
+     * <code>ResourceBundle.Control</code> collaborates with the factory
+     * methods for loading resource bundles. The default implementation of
+     * the callback methods provides the information necessary for the
+     * factory methods to perform the <a
+     * href="./ResourceBundle.html#default_behavior">default behavior</a>.
+     *
+     * <p>In addition to the callback methods, the {@link
+     * #toBundleName(String, Locale) toBundleName} and {@link
+     * #toResourceName(String, String) toResourceName} methods are defined
+     * primarily for convenience in implementing the callback
+     * methods. However, the <code>toBundleName</code> method could be
+     * overridden to provide different conventions in the organization and
+     * packaging of localized resources.  The <code>toResourceName</code>
+     * method is <code>final</code> to avoid use of wrong resource and class
+     * name separators.
+     *
+     * <p>Two factory methods, {@link #getControl(List)} and {@link
+     * #getNoFallbackControl(List)}, provide
+     * <code>ResourceBundle.Control</code> instances that implement common
+     * variations of the default bundle loading process.
+     *
+     * <p>The formats returned by the {@link Control#getFormats(String)
+     * getFormats} method and candidate locales returned by the {@link
+     * ResourceBundle.Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} method must be consistent in all
+     * <code>ResourceBundle.getBundle</code> invocations for the same base
+     * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
+     * may return unintended bundles. For example, if only
+     * <code>"java.class"</code> is returned by the <code>getFormats</code>
+     * method for the first call to <code>ResourceBundle.getBundle</code>
+     * and only <code>"java.properties"</code> for the second call, then the
+     * second call will return the class-based one that has been cached
+     * during the first call.
+     *
+     * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
+     * if it's simultaneously used by multiple threads.
+     * <code>ResourceBundle.getBundle</code> does not synchronize to call
+     * the <code>ResourceBundle.Control</code> methods. The default
+     * implementations of the methods are thread-safe.
+     *
+     * <p>Applications can specify <code>ResourceBundle.Control</code>
+     * instances returned by the <code>getControl</code> factory methods or
+     * created from a subclass of <code>ResourceBundle.Control</code> to
+     * customize the bundle loading process. The following are examples of
+     * changing the default bundle loading process.
+     *
+     * <p><b>Example 1</b>
+     *
+     * <p>The following code lets <code>ResourceBundle.getBundle</code> look
+     * up only properties-based resources.
+     *
+     * <pre>
+     * import java.util.*;
+     * import static java.util.ResourceBundle.Control.*;
+     * ...
+     * ResourceBundle bundle =
+     *   ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
+     *                            ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
+     * </pre>
+     *
+     * Given the resource bundles in the <a
+     * href="./ResourceBundle.html#default_behavior_example">example</a> in
+     * the <code>ResourceBundle.getBundle</code> description, this
+     * <code>ResourceBundle.getBundle</code> call loads
+     * <code>MyResources_fr_CH.properties</code> whose parent is
+     * <code>MyResources_fr.properties</code> whose parent is
+     * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
+     * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
+     *
+     * <p><b>Example 2</b>
+     *
+     * <p>The following is an example of loading XML-based bundles
+     * using {@link Properties#loadFromXML(java.io.InputStream)
+     * Properties.loadFromXML}.
+     *
+     * <pre>
+     * ResourceBundle rb = ResourceBundle.getBundle("Messages",
+     *     new ResourceBundle.Control() {
+     *         public List&lt;String&gt; getFormats(String baseName) {
+     *             if (baseName == null)
+     *                 throw new NullPointerException();
+     *             return Arrays.asList("xml");
+     *         }
+     *         public ResourceBundle newBundle(String baseName,
+     *                                         Locale locale,
+     *                                         String format,
+     *                                         ClassLoader loader,
+     *                                         boolean reload)
+     *                          throws IllegalAccessException,
+     *                                 InstantiationException,
+     *                                 IOException {
+     *             if (baseName == null || locale == null
+     *                   || format == null || loader == null)
+     *                 throw new NullPointerException();
+     *             ResourceBundle bundle = null;
+     *             if (format.equals("xml")) {
+     *                 String bundleName = toBundleName(baseName, locale);
+     *                 String resourceName = toResourceName(bundleName, format);
+     *                 InputStream stream = null;
+     *                 if (reload) {
+     *                     URL url = loader.getResource(resourceName);
+     *                     if (url != null) {
+     *                         URLConnection connection = url.openConnection();
+     *                         if (connection != null) {
+     *                             // Disable caches to get fresh data for
+     *                             // reloading.
+     *                             connection.setUseCaches(false);
+     *                             stream = connection.getInputStream();
+     *                         }
+     *                     }
+     *                 } else {
+     *                     stream = loader.getResourceAsStream(resourceName);
+     *                 }
+     *                 if (stream != null) {
+     *                     BufferedInputStream bis = new BufferedInputStream(stream);
+     *                     bundle = new XMLResourceBundle(bis);
+     *                     bis.close();
+     *                 }
+     *             }
+     *             return bundle;
+     *         }
+     *     });
+     *
+     * ...
+     *
+     * private static class XMLResourceBundle extends ResourceBundle {
+     *     private Properties props;
+     *     XMLResourceBundle(InputStream stream) throws IOException {
+     *         props = new Properties();
+     *         props.loadFromXML(stream);
+     *     }
+     *     protected Object handleGetObject(String key) {
+     *         return props.getProperty(key);
+     *     }
+     *     public Enumeration&lt;String&gt; getKeys() {
+     *         ...
+     *     }
+     * }
+     * </pre>
+     *
+     * @since 1.6
+     * @revised 9
+     */
+    public static class Control {
+        /**
+         * The default format <code>List</code>, which contains the strings
+         * <code>"java.class"</code> and <code>"java.properties"</code>, in
+         * this order. This <code>List</code> is unmodifiable.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_DEFAULT
+            = List.of("java.class", "java.properties");
+
+        /**
+         * The class-only format <code>List</code> containing
+         * <code>"java.class"</code>. This <code>List</code> is unmodifiable.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_CLASS = List.of("java.class");
+
+        /**
+         * The properties-only format <code>List</code> containing
+         * <code>"java.properties"</code>. This <code>List</code> is unmodifiable.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_PROPERTIES
+            = List.of("java.properties");
+
+        /**
+         * The time-to-live constant for not caching loaded resource bundle
+         * instances.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_DONT_CACHE = -1;
+
+        /**
+         * The time-to-live constant for disabling the expiration control
+         * for loaded resource bundle instances in the cache.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_NO_EXPIRATION_CONTROL = -2;
+
+        private static final Control INSTANCE = new Control();
+
+        /**
+         * Sole constructor. (For invocation by subclass constructors,
+         * typically implicit.)
+         */
+        protected Control() {
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code>. The <code>formats</code> must be equal to
+         * one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link
+         * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
+         * instances returned by this method are singletons and thread-safe.
+         *
+         * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
+         * instantiating the <code>ResourceBundle.Control</code> class,
+         * except that this method returns a singleton.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code>
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return SingleFormatControl.PROPERTIES_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return SingleFormatControl.CLASS_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return Control.INSTANCE;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code> and the {@link
+         * Control#getFallbackLocale(String, Locale) getFallbackLocale}
+         * method returns <code>null</code>. The <code>formats</code> must
+         * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
+         * <code>ResourceBundle.Control</code> instances returned by this
+         * method are singletons and thread-safe.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code> with no fallback
+         *        <code>Locale</code> support
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getNoFallbackControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return NoFallbackControl.NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>String</code>s containing
+         * formats to be used to load resource bundles for the given
+         * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
+         * factory method tries to load resource bundles with formats in the
+         * order specified by the list. The list returned by this method
+         * must have at least one <code>String</code>. The predefined
+         * formats are <code>"java.class"</code> for class-based resource
+         * bundles and <code>"java.properties"</code> for {@linkplain
+         * PropertyResourceBundle properties-based} ones. Strings starting
+         * with <code>"java."</code> are reserved for future extensions and
+         * must not be used by application-defined formats.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>.  However, the returned <code>List</code> must
+         * not be mutated after it has been returned by
+         * <code>getFormats</code>.
+         *
+         * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
+         * that the <code>ResourceBundle.getBundle</code> factory method
+         * looks up first class-based resource bundles, then
+         * properties-based ones.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully qualified class
+         *        name
+         * @return a <code>List</code> of <code>String</code>s containing
+         *        formats for loading resource bundles.
+         * @exception NullPointerException
+         *        if <code>baseName</code> is null
+         * @see #FORMAT_DEFAULT
+         * @see #FORMAT_CLASS
+         * @see #FORMAT_PROPERTIES
+         */
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return FORMAT_DEFAULT;
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>Locale</code>s as candidate
+         * locales for <code>baseName</code> and <code>locale</code>. This
+         * method is called by the <code>ResourceBundle.getBundle</code>
+         * factory method each time the factory method tries finding a
+         * resource bundle for a target <code>Locale</code>.
+         *
+         * <p>The sequence of the candidate locales also corresponds to the
+         * runtime resource lookup path (also known as the <I>parent
+         * chain</I>), if the corresponding resource bundles for the
+         * candidate locales exist and their parents are not defined by
+         * loaded resource bundles themselves.  The last element of the list
+         * must be a {@linkplain Locale#ROOT root locale} if it is desired to
+         * have the base bundle as the terminal of the parent chain.
+         *
+         * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
+         * root locale), a <code>List</code> containing only the root
+         * <code>Locale</code> must be returned. In this case, the
+         * <code>ResourceBundle.getBundle</code> factory method loads only
+         * the base bundle as the resulting resource bundle.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>. However, the returned <code>List</code> must not
+         * be mutated after it has been returned by
+         * <code>getCandidateLocales</code>.
+         *
+         * <p>The default implementation returns a <code>List</code> containing
+         * <code>Locale</code>s using the rules described below.  In the
+         * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
+         * respectively represent non-empty language, script, country, and
+         * variant.  For example, [<em>L</em>, <em>C</em>] represents a
+         * <code>Locale</code> that has non-empty values only for language and
+         * country.  The form <em>L</em>("xx") represents the (non-empty)
+         * language value is "xx".  For all cases, <code>Locale</code>s whose
+         * final component values are empty strings are omitted.
+         *
+         * <ol><li>For an input <code>Locale</code> with an empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * one by one as below:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>] </li>
+         * <li> [<em>L</em>, <em>C</em>] </li>
+         * <li> [<em>L</em>] </li>
+         * <li> <code>Locale.ROOT</code> </li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a non-empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * up to language, then append candidates generated from the
+         * <code>Locale</code> with country and variant restored:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a variant value consisting
+         * of multiple subtags separated by underscore, generate candidate
+         * <code>Locale</code>s by omitting the variant subtags one by one, then
+         * insert them after every occurrence of <code> Locale</code>s with the
+         * full variant value in the original list.  For example, if
+         * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
+         * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
+         * "Hant" (Traditional) might be supplied, depending on the country.
+         * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
+         * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
+         * or "TW" (Taiwan), "Hant" is supplied.  For all other countries or when the country
+         * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
+         * </code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * For <code>Locale("zh", "TW")</code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
+         * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
+         * Nynorsk.  When a locale's language is "nn", the standard candidate
+         * list is generated up to [<em>L</em>("nn")], and then the following
+         * candidates are added:
+         *
+         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
+         * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
+         * followed.
+         *
+         * <p>Also, Java treats the language "no" as a synonym of Norwegian
+         * Bokm&#xE5;l "nb".  Except for the single case <code>Locale("no",
+         * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
+         * has language "no" or "nb", candidate <code>Locale</code>s with
+         * language code "no" and "nb" are interleaved, first using the
+         * requested language, then using its synonym. For example,
+         * <code>Locale("nb", "NO", "POSIX")</code> generates the following
+         * candidate list:
+         *
+         * <ul>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("nb")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
+         * except that locales with "no" would appear before the corresponding
+         * locales with "nb".</li>
+         * </ol>
+         *
+         * <p>The default implementation uses an {@link ArrayList} that
+         * overriding implementations may modify before returning it to the
+         * caller. However, a subclass must not modify it after it has
+         * been returned by <code>getCandidateLocales</code>.
+         *
+         * <p>For example, if the given <code>baseName</code> is "Messages"
+         * and the given <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then a
+         * <code>List</code> of <code>Locale</code>s:
+         * <pre>
+         *     Locale("ja", "", "XX")
+         *     Locale("ja")
+         *     Locale.ROOT
+         * </pre>
+         * is returned. And if the resource bundles for the "ja" and
+         * "" <code>Locale</code>s are found, then the runtime resource
+         * lookup path (parent chain) is:
+         * <pre>{@code
+         *     Messages_ja -> Messages
+         * }</pre>
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle is desired
+         * @return a <code>List</code> of candidate
+         *        <code>Locale</code>s for the given <code>locale</code>
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
+        }
+
+        private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
+
+        private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
+            protected List<Locale> createObject(BaseLocale base) {
+                String language = base.getLanguage();
+                String script = base.getScript();
+                String region = base.getRegion();
+                String variant = base.getVariant();
+
+                // Special handling for Norwegian
+                boolean isNorwegianBokmal = false;
+                boolean isNorwegianNynorsk = false;
+                if (language.equals("no")) {
+                    if (region.equals("NO") && variant.equals("NY")) {
+                        variant = "";
+                        isNorwegianNynorsk = true;
+                    } else {
+                        isNorwegianBokmal = true;
+                    }
+                }
+                if (language.equals("nb") || isNorwegianBokmal) {
+                    List<Locale> tmpList = getDefaultList("nb", script, region, variant);
+                    // Insert a locale replacing "nb" with "no" for every list entry
+                    List<Locale> bokmalList = new LinkedList<>();
+                    for (Locale l : tmpList) {
+                        bokmalList.add(l);
+                        if (l.getLanguage().isEmpty()) {
+                            break;
+                        }
+                        bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
+                                l.getVariant(), null));
+                    }
+                    return bokmalList;
+                } else if (language.equals("nn") || isNorwegianNynorsk) {
+                    // Insert no_NO_NY, no_NO, no after nn
+                    List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
+                    int idx = nynorskList.size() - 1;
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
+                    nynorskList.add(idx++, Locale.getInstance("no", "", ""));
+                    return nynorskList;
+                }
+                // Special handling for Chinese
+                else if (language.equals("zh")) {
+                    if (script.isEmpty() && !region.isEmpty()) {
+                        // Supply script for users who want to use zh_Hans/zh_Hant
+                        // as bundle names (recommended for Java7+)
+                        switch (region) {
+                        case "TW":
+                        case "HK":
+                        case "MO":
+                            script = "Hant";
+                            break;
+                        case "CN":
+                        case "SG":
+                            script = "Hans";
+                            break;
+                        }
+                    }
+                }
+
+                return getDefaultList(language, script, region, variant);
+            }
+
+            private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
+                List<String> variants = null;
+
+                if (!variant.isEmpty()) {
+                    variants = new LinkedList<>();
+                    int idx = variant.length();
+                    while (idx != -1) {
+                        variants.add(variant.substring(0, idx));
+                        idx = variant.lastIndexOf('_', --idx);
+                    }
+                }
+
+                List<Locale> list = new LinkedList<>();
+
+                if (variants != null) {
+                    for (String v : variants) {
+                        list.add(Locale.getInstance(language, script, region, v, null));
+                    }
+                }
+                if (!region.isEmpty()) {
+                    list.add(Locale.getInstance(language, script, region, "", null));
+                }
+                if (!script.isEmpty()) {
+                    list.add(Locale.getInstance(language, script, "", "", null));
+                    // Special handling for Chinese
+                    if (language.equals("zh")) {
+                        if (region.isEmpty()) {
+                            // Supply region(country) for users who still package Chinese
+                            // bundles using old convension.
+                            switch (script) {
+                                case "Hans":
+                                    region = "CN";
+                                    break;
+                                case "Hant":
+                                    region = "TW";
+                                    break;
+                            }
+                        }
+                    }
+
+                    // With script, after truncating variant, region and script,
+                    // start over without script.
+                    if (variants != null) {
+                        for (String v : variants) {
+                            list.add(Locale.getInstance(language, "", region, v, null));
+                        }
+                    }
+                    if (!region.isEmpty()) {
+                        list.add(Locale.getInstance(language, "", region, "", null));
+                    }
+                }
+                if (!language.isEmpty()) {
+                    list.add(Locale.getInstance(language, "", "", "", null));
+                }
+                // Add root locale at the end
+                list.add(Locale.ROOT);
+
+                return list;
+            }
+        }
+
+        /**
+         * Returns a <code>Locale</code> to be used as a fallback locale for
+         * further resource bundle searches by the
+         * <code>ResourceBundle.getBundle</code> factory method. This method
+         * is called from the factory method every time when no resulting
+         * resource bundle has been found for <code>baseName</code> and
+         * <code>locale</code>, where locale is either the parameter for
+         * <code>ResourceBundle.getBundle</code> or the previous fallback
+         * locale returned by this method.
+         *
+         * <p>The method returns <code>null</code> if no further fallback
+         * search is desired.
+         *
+         * <p>The default implementation returns the {@linkplain
+         * Locale#getDefault() default <code>Locale</code>} if the given
+         * <code>locale</code> isn't the default one.  Otherwise,
+         * <code>null</code> is returned.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @param locale
+         *        the <code>Locale</code> for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @return a <code>Locale</code> for the fallback search,
+         *        or <code>null</code> if no further fallback search
+         *        is desired.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            Locale defaultLocale = Locale.getDefault();
+            return locale.equals(defaultLocale) ? null : defaultLocale;
+        }
+
+        /**
+         * Instantiates a resource bundle for the given bundle name of the
+         * given format and locale, using the given class loader if
+         * necessary. This method returns <code>null</code> if there is no
+         * resource bundle available for the given parameters. If a resource
+         * bundle can't be instantiated due to an unexpected error, the
+         * error must be reported by throwing an <code>Error</code> or
+         * <code>Exception</code> rather than simply returning
+         * <code>null</code>.
+         *
+         * <p>If the <code>reload</code> flag is <code>true</code>, it
+         * indicates that this method is being called because the previously
+         * loaded resource bundle has expired.
+         *
+         * <p>The default implementation instantiates a
+         * <code>ResourceBundle</code> as follows.
+         *
+         * <ul>
+         *
+         * <li>The bundle name is obtained by calling {@link
+         * #toBundleName(String, Locale) toBundleName(baseName,
+         * locale)}.</li>
+         *
+         * <li>If <code>format</code> is <code>"java.class"</code>, the
+         * {@link Class} specified by the bundle name is loaded with the
+         * given class loader. If the {@code Class} is found and accessible
+         * then the <code>ResourceBundle</code> is instantiated.  The
+         * resource bundle is accessible if the package of the bundle class file
+         * is open unconditionally; otherwise, {@code IllegalAccessException}
+         * will be thrown.
+         * Note that the <code>reload</code> flag is ignored for loading
+         * class-based resource bundles in this default implementation.
+         * </li>
+         *
+         * <li>If <code>format</code> is <code>"java.properties"</code>,
+         * {@link #toResourceName(String, String) toResourceName(bundlename,
+         * "properties")} is called to get the resource name.
+         * If <code>reload</code> is <code>true</code>, {@link
+         * ClassLoader#getResource(String) load.getResource} is called
+         * to get a {@link URL} for creating a {@link
+         * URLConnection}. This <code>URLConnection</code> is used to
+         * {@linkplain URLConnection#setUseCaches(boolean) disable the
+         * caches} of the underlying resource loading layers,
+         * and to {@linkplain URLConnection#getInputStream() get an
+         * <code>InputStream</code>}.
+         * Otherwise, {@link ClassLoader#getResourceAsStream(String)
+         * loader.getResourceAsStream} is called to get an {@link
+         * InputStream}. Then, a {@link
+         * PropertyResourceBundle} is constructed with the
+         * <code>InputStream</code>.</li>
+         *
+         * <li>If <code>format</code> is neither <code>"java.class"</code>
+         * nor <code>"java.properties"</code>, an
+         * <code>IllegalArgumentException</code> is thrown.</li>
+         *
+         * </ul>
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which the resource bundle should be
+         *        instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param reload
+         *        the flag to indicate bundle reloading; <code>true</code>
+         *        if reloading an expired resource bundle,
+         *        <code>false</code> otherwise
+         * @return the resource bundle instance,
+         *        or <code>null</code> if none could be found.
+         * @exception NullPointerException
+         *        if <code>bundleName</code>, <code>locale</code>,
+         *        <code>format</code>, or <code>loader</code> is
+         *        <code>null</code>, or if <code>null</code> is returned by
+         *        {@link #toBundleName(String, Locale) toBundleName}
+         * @exception IllegalArgumentException
+         *        if <code>format</code> is unknown, or if the resource
+         *        found for the given parameters contains malformed data.
+         * @exception ClassCastException
+         *        if the loaded class cannot be cast to <code>ResourceBundle</code>
+         * @exception IllegalAccessException
+         *        if the class or its nullary constructor is not
+         *        accessible.
+         * @exception InstantiationException
+         *        if the instantiation of a class fails for some other
+         *        reason.
+         * @exception ExceptionInInitializerError
+         *        if the initialization provoked by this method fails.
+         * @exception SecurityException
+         *        If a security manager is present and creation of new
+         *        instances is denied. See {@link Class#newInstance()}
+         *        for details.
+         * @exception IOException
+         *        if an error occurred when reading resources using
+         *        any I/O operations
+         * @revised 9
+         */
+        public ResourceBundle newBundle(String baseName, Locale locale, String format,
+                                        ClassLoader loader, boolean reload)
+                    throws IllegalAccessException, InstantiationException, IOException {
+            /*
+             * Legacy mechanism to locate resource bundle in unnamed module only
+             * that is visible to the given loader and accessible to the given caller.
+             */
+            String bundleName = toBundleName(baseName, locale);
+            ResourceBundle bundle = null;
+            if (format.equals("java.class")) {
+                try {
+                    Class<?> c = loader.loadClass(bundleName);
+                    // If the class isn't a ResourceBundle subclass, throw a
+                    // ClassCastException.
+                    if (ResourceBundle.class.isAssignableFrom(c)) {
+                        @SuppressWarnings("unchecked")
+                        Class<ResourceBundle> bundleClass = (Class<ResourceBundle>)c;
+                        // Android-removed: modules are not supported.
+                        /*
+                        Module m = bundleClass.getModule();
+
+                        // To access a resource bundle in a named module,
+                        // either class-based or properties-based, the resource
+                        // bundle must be opened unconditionally,
+                        // same rule as accessing a resource file.
+                        if (m.isNamed() && !m.isOpen(bundleClass.getPackageName())) {
+                            throw new IllegalAccessException("unnamed module can't load " +
+                                bundleClass.getName() + " in " + m.toString());
+                        }
+                        */
+                        try {
+                            // bundle in a unnamed module
+                            Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
+                            if (!Modifier.isPublic(ctor.getModifiers())) {
+                                return null;
+                            }
+
+                            // java.base may not be able to read the bundleClass's module.
+                            PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
+                            AccessController.doPrivileged(pa1);
+                            bundle = ctor.newInstance((Object[]) null);
+                        } catch (InvocationTargetException e) {
+                            uncheckedThrow(e);
+                        }
+                    } else {
+                        throw new ClassCastException(c.getName()
+                                + " cannot be cast to ResourceBundle");
+                    }
+                } catch (ClassNotFoundException|NoSuchMethodException e) {
+                }
+            } else if (format.equals("java.properties")) {
+                final String resourceName = toResourceName0(bundleName, "properties");
+                if (resourceName == null) {
+                    return bundle;
+                }
+
+                final boolean reloadFlag = reload;
+                InputStream stream = null;
+                try {
+                    stream = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<>() {
+                            public InputStream run() throws IOException {
+                                URL url = loader.getResource(resourceName);
+                                if (url == null) return null;
+
+                                URLConnection connection = url.openConnection();
+                                if (reloadFlag) {
+                                    // Disable caches to get fresh data for
+                                    // reloading.
+                                    connection.setUseCaches(false);
+                                }
+                                return connection.getInputStream();
+                            }
+                        });
+                } catch (PrivilegedActionException e) {
+                    throw (IOException) e.getException();
+                }
+                if (stream != null) {
+                    try {
+                        // Android-changed: Use UTF-8 for property based resources. b/26879578
+                        // bundle = new PropertyResourceBundle(stream);
+                        bundle = new PropertyResourceBundle(
+                                new InputStreamReader(stream, StandardCharsets.UTF_8));
+                    } finally {
+                        stream.close();
+                    }
+                }
+            } else {
+                throw new IllegalArgumentException("unknown format: " + format);
+            }
+            return bundle;
+        }
+
+        /**
+         * Returns the time-to-live (TTL) value for resource bundles that
+         * are loaded under this
+         * <code>ResourceBundle.Control</code>. Positive time-to-live values
+         * specify the number of milliseconds a bundle can remain in the
+         * cache without being validated against the source data from which
+         * it was constructed. The value 0 indicates that a bundle must be
+         * validated each time it is retrieved from the cache. {@link
+         * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
+         * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
+         * that loaded resource bundles are put in the cache with no
+         * expiration control.
+         *
+         * <p>The expiration affects only the bundle loading process by the
+         * <code>ResourceBundle.getBundle</code> factory method.  That is,
+         * if the factory method finds a resource bundle in the cache that
+         * has expired, the factory method calls the {@link
+         * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+         * long) needsReload} method to determine whether the resource
+         * bundle needs to be reloaded. If <code>needsReload</code> returns
+         * <code>true</code>, the cached resource bundle instance is removed
+         * from the cache. Otherwise, the instance stays in the cache,
+         * updated with the new TTL value returned by this method.
+         *
+         * <p>All cached resource bundles are subject to removal from the
+         * cache due to memory constraints of the runtime environment.
+         * Returning a large positive value doesn't mean to lock loaded
+         * resource bundles in the cache.
+         *
+         * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
+         *
+         * @param baseName
+         *        the base name of the resource bundle for which the
+         *        expiration value is specified.
+         * @param locale
+         *        the locale of the resource bundle for which the
+         *        expiration value is specified.
+         * @return the time (0 or a positive millisecond offset from the
+         *        cached time) to get loaded bundles expired in the cache,
+         *        {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
+         *        expiration control, or {@link #TTL_DONT_CACHE} to disable
+         *        caching.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public long getTimeToLive(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return TTL_NO_EXPIRATION_CONTROL;
+        }
+
+        /**
+         * Determines if the expired <code>bundle</code> in the cache needs
+         * to be reloaded based on the loading time given by
+         * <code>loadTime</code> or some other criteria. The method returns
+         * <code>true</code> if reloading is required; <code>false</code>
+         * otherwise. <code>loadTime</code> is a millisecond offset since
+         * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
+         * Epoch</a>.
+         *
+         * <p>
+         * The calling <code>ResourceBundle.getBundle</code> factory method
+         * calls this method on the <code>ResourceBundle.Control</code>
+         * instance used for its current invocation, not on the instance
+         * used in the invocation that originally loaded the resource
+         * bundle.
+         *
+         * <p>The default implementation compares <code>loadTime</code> and
+         * the last modified time of the source data of the resource
+         * bundle. If it's determined that the source data has been modified
+         * since <code>loadTime</code>, <code>true</code> is
+         * returned. Otherwise, <code>false</code> is returned. This
+         * implementation assumes that the given <code>format</code> is the
+         * same string as its file suffix if it's not one of the default
+         * formats, <code>"java.class"</code> or
+         * <code>"java.properties"</code>.
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a
+         *        fully qualified class name
+         * @param locale
+         *        the locale for which the resource bundle
+         *        should be instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param bundle
+         *        the resource bundle instance that has been expired
+         *        in the cache
+         * @param loadTime
+         *        the time when <code>bundle</code> was loaded and put
+         *        in the cache
+         * @return <code>true</code> if the expired bundle needs to be
+         *        reloaded; <code>false</code> otherwise.
+         * @exception NullPointerException
+         *        if <code>baseName</code>, <code>locale</code>,
+         *        <code>format</code>, <code>loader</code>, or
+         *        <code>bundle</code> is <code>null</code>
+         */
+        public boolean needsReload(String baseName, Locale locale,
+                                   String format, ClassLoader loader,
+                                   ResourceBundle bundle, long loadTime) {
+            if (bundle == null) {
+                throw new NullPointerException();
+            }
+            if (format.equals("java.class") || format.equals("java.properties")) {
+                format = format.substring(5);
+            }
+            boolean result = false;
+            try {
+                String resourceName = toResourceName0(toBundleName(baseName, locale), format);
+                if (resourceName == null) {
+                    return result;
+                }
+                URL url = loader.getResource(resourceName);
+                if (url != null) {
+                    long lastModified = 0;
+                    URLConnection connection = url.openConnection();
+                    if (connection != null) {
+                        // disable caches to get the correct data
+                        connection.setUseCaches(false);
+                        if (connection instanceof JarURLConnection) {
+                            JarEntry ent = ((JarURLConnection)connection).getJarEntry();
+                            if (ent != null) {
+                                lastModified = ent.getTime();
+                                if (lastModified == -1) {
+                                    lastModified = 0;
+                                }
+                            }
+                        } else {
+                            lastModified = connection.getLastModified();
+                        }
+                    }
+                    result = lastModified >= loadTime;
+                }
+            } catch (NullPointerException npe) {
+                throw npe;
+            } catch (Exception e) {
+                // ignore other exceptions
+            }
+            return result;
+        }
+
+        /**
+         * Converts the given <code>baseName</code> and <code>locale</code>
+         * to the bundle name. This method is called from the default
+         * implementation of the {@link #newBundle(String, Locale, String,
+         * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
+         * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
+         * methods.
+         *
+         * <p>This implementation returns the following value:
+         * <pre>
+         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+         * </pre>
+         * where <code>language</code>, <code>script</code>, <code>country</code>,
+         * and <code>variant</code> are the language, script, country, and variant
+         * values of <code>locale</code>, respectively. Final component values that
+         * are empty Strings are omitted along with the preceding '_'.  When the
+         * script is empty, the script value is omitted along with the preceding '_'.
+         * If all of the values are empty strings, then <code>baseName</code>
+         * is returned.
+         *
+         * <p>For example, if <code>baseName</code> is
+         * <code>"baseName"</code> and <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then
+         * <code>"baseName_ja_&thinsp;_XX"</code> is returned. If the given
+         * locale is <code>Locale("en")</code>, then
+         * <code>"baseName_en"</code> is returned.
+         *
+         * <p>Overriding this method allows applications to use different
+         * conventions in the organization and packaging of localized
+         * resources.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle should be
+         *        loaded
+         * @return the bundle name for the resource bundle
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public String toBundleName(String baseName, Locale locale) {
+            if (locale == Locale.ROOT) {
+                return baseName;
+            }
+
+            String language = locale.getLanguage();
+            String script = locale.getScript();
+            String country = locale.getCountry();
+            String variant = locale.getVariant();
+
+            if (language == "" && country == "" && variant == "") {
+                return baseName;
+            }
+
+            StringBuilder sb = new StringBuilder(baseName);
+            sb.append('_');
+            if (script != "") {
+                if (variant != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country);
+                } else {
+                    sb.append(language).append('_').append(script);
+                }
+            } else {
+                if (variant != "") {
+                    sb.append(language).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(country);
+                } else {
+                    sb.append(language);
+                }
+            }
+            return sb.toString();
+
+        }
+
+        /**
+         * Converts the given {@code bundleName} to the form required
+         * by the {@link ClassLoader#getResource ClassLoader.getResource}
+         * method by replacing all occurrences of {@code '.'} in
+         * {@code bundleName} with {@code '/'} and appending a
+         * {@code '.'} and the given file {@code suffix}. For
+         * example, if {@code bundleName} is
+         * {@code "foo.bar.MyResources_ja_JP"} and {@code suffix}
+         * is {@code "properties"}, then
+         * {@code "foo/bar/MyResources_ja_JP.properties"} is returned.
+         *
+         * @param bundleName
+         *        the bundle name
+         * @param suffix
+         *        the file type suffix
+         * @return the converted resource name
+         * @exception NullPointerException
+         *         if {@code bundleName} or {@code suffix}
+         *         is {@code null}
+         */
+        public final String toResourceName(String bundleName, String suffix) {
+            StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+            sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+            return sb.toString();
+        }
+
+        private String toResourceName0(String bundleName, String suffix) {
+            // application protocol check
+            if (bundleName.contains("://")) {
+                return null;
+            } else {
+                return toResourceName(bundleName, suffix);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
+        if (t != null)
+            throw (T)t;
+        else
+            throw new Error("Unknown Exception");
+    }
+
+    private static class SingleFormatControl extends Control {
+        private static final Control PROPERTIES_ONLY
+            = new SingleFormatControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY
+            = new SingleFormatControl(FORMAT_CLASS);
+
+        private final List<String> formats;
+
+        protected SingleFormatControl(List<String> formats) {
+            this.formats = formats;
+        }
+
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return formats;
+        }
+    }
+
+    private static final class NoFallbackControl extends SingleFormatControl {
+        private static final Control NO_FALLBACK
+            = new NoFallbackControl(FORMAT_DEFAULT);
+
+        private static final Control PROPERTIES_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_CLASS);
+
+        protected NoFallbackControl(List<String> formats) {
+            super(formats);
+        }
+
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return null;
+        }
+    }
+
+    // Android-removed: modules are not supported.
+    /*
+    private static class ResourceBundleProviderHelper {
+        /**
+         * Returns a new ResourceBundle instance of the given bundleClass
+         *
+        static ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+            try {
+                @SuppressWarnings("unchecked")
+                Constructor<? extends ResourceBundle> ctor =
+                    bundleClass.getConstructor();
+                if (!Modifier.isPublic(ctor.getModifiers())) {
+                    return null;
+                }
+                // java.base may not be able to read the bundleClass's module.
+                PrivilegedAction<Void> pa = () -> { ctor.setAccessible(true); return null;};
+                AccessController.doPrivileged(pa);
+                try {
+                    return ctor.newInstance((Object[]) null);
+                } catch (InvocationTargetException e) {
+                    uncheckedThrow(e);
+                } catch (InstantiationException | IllegalAccessException e) {
+                    throw new InternalError(e);
+                }
+            } catch (NoSuchMethodException e) {
+                throw new InternalError(e);
+            }
+            return null;
+        }
+
+        /**
+         * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
+         * the given {@code module}. If not found, search the bundle class
+         * that is visible from the module's class loader.
+         *
+         * The caller module is used for access check only.
+         *
+        static ResourceBundle loadResourceBundle(Module callerModule,
+                                                 Module module,
+                                                 String baseName,
+                                                 Locale locale)
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+            try {
+                PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName);
+                Class<?> c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                trace("local in %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+
+                if (c == null) {
+                    // if not found from the given module, locate resource bundle
+                    // that is visible to the module's class loader
+                    ClassLoader loader = getLoader(module);
+                    if (loader != null) {
+                        c = Class.forName(bundleName, false, loader);
+                    } else {
+                        c = BootLoader.loadClassOrNull(bundleName);
+                    }
+                    trace("loader for %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+                }
+
+                if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+                    @SuppressWarnings("unchecked")
+                    Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                    Module m = bundleClass.getModule();
+                    if (!isAccessible(callerModule, m, bundleClass.getPackageName())) {
+                        trace("   %s does not have access to %s/%s%n", callerModule,
+                              m.getName(), bundleClass.getPackageName());
+                        return null;
+                    }
+
+                    return newResourceBundle(bundleClass);
+                }
+            } catch (ClassNotFoundException e) {}
+            return null;
+        }
+
+        /**
+         * Tests if resources of the given package name from the given module are
+         * open to the caller module.
+         *
+        static boolean isAccessible(Module callerModule, Module module, String pn) {
+            if (!module.isNamed() || callerModule == module)
+                return true;
+
+            return module.isOpen(pn, callerModule);
+        }
+
+        /**
+         * Loads properties of the given {@code bundleName} local in the given
+         * {@code module}.  If the .properties is not found or not open
+         * to the caller module to access, it will find the resource that
+         * is visible to the module's class loader.
+         *
+         * The caller module is used for access check only.
+         *
+        static ResourceBundle loadPropertyResourceBundle(Module callerModule,
+                                                         Module module,
+                                                         String baseName,
+                                                         Locale locale)
+            throws IOException
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+
+            PrivilegedAction<InputStream> pa = () -> {
+                try {
+                    String resourceName = Control.INSTANCE
+                        .toResourceName0(bundleName, "properties");
+                    if (resourceName == null) {
+                        return null;
+                    }
+                    trace("local in %s %s caller %s%n", module, resourceName, callerModule);
+
+                    // if the package is in the given module but not opened
+                    // locate it from the given module first.
+                    String pn = toPackageName(bundleName);
+                    trace("   %s/%s is accessible to %s : %s%n",
+                            module.getName(), pn, callerModule,
+                            isAccessible(callerModule, module, pn));
+                    if (isAccessible(callerModule, module, pn)) {
+                        InputStream in = module.getResourceAsStream(resourceName);
+                        if (in != null) {
+                            return in;
+                        }
+                    }
+
+                    ClassLoader loader = module.getClassLoader();
+                    trace("loader for %s %s caller %s%n", module, resourceName, callerModule);
+
+                    try {
+                        if (loader != null) {
+                            return loader.getResourceAsStream(resourceName);
+                        } else {
+                            URL url = BootLoader.findResource(resourceName);
+                            if (url != null) {
+                                return url.openStream();
+                            }
+                        }
+                    } catch (Exception e) {}
+                    return null;
+
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            };
+
+            try (InputStream stream = AccessController.doPrivileged(pa)) {
+                if (stream != null) {
+                    return new PropertyResourceBundle(stream);
+                } else {
+                    return null;
+                }
+            } catch (UncheckedIOException e) {
+                throw e.getCause();
+            }
+        }
+
+        private static String toPackageName(String bundleName) {
+            int i = bundleName.lastIndexOf('.');
+            return i != -1 ? bundleName.substring(0, i) : "";
+        }
+    }
+    */
+
+    private static final boolean TRACE_ON = Boolean.valueOf(
+        GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false"));
+
+    private static void trace(String format, Object... params) {
+        if (TRACE_ON)
+            System.out.format(format, params);
+    }
+}
diff --git a/android-35/java/util/ReverseOrderDequeView.java b/android-35/java/util/ReverseOrderDequeView.java
new file mode 100644
index 0000000..695db6a
--- /dev/null
+++ b/android-35/java/util/ReverseOrderDequeView.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * Provides a reverse-ordered view of any Deque. Not serializable.
+ */
+class ReverseOrderDequeView<E> implements Deque<E> {
+    final Deque<E> base;
+
+    private ReverseOrderDequeView(Deque<E> deque) {
+        base = deque;
+    }
+
+    public static <T> Deque<T> of(Deque<T> deque) {
+        if (deque instanceof ReverseOrderDequeView<T> rodv) {
+            return rodv.base;
+        } else {
+            return new ReverseOrderDequeView<>(deque);
+        }
+    }
+
+    // ========== Iterable ==========
+
+    public void forEach(Consumer<? super E> action) {
+        for (E e : this)
+            action.accept(e);
+    }
+
+    public Iterator<E> iterator() {
+        return base.descendingIterator();
+    }
+
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.ORDERED);
+    }
+
+    // ========== Collection ==========
+
+    public boolean add(E e) {
+        base.addFirst(e);
+        return true;
+    }
+
+    public boolean addAll(Collection<? extends E> c) {
+        boolean modified = false;
+        for (E e : c) {
+            base.addFirst(e);
+            modified = true;
+        }
+        return modified;
+    }
+
+    public void clear() {
+        base.clear();
+    }
+
+    public boolean contains(Object o) {
+        return base.contains(o);
+    }
+
+    public boolean containsAll(Collection<?> c) {
+        return base.containsAll(c);
+    }
+
+    public boolean isEmpty() {
+        return base.isEmpty();
+    }
+
+    public Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+
+    // copied from AbstractCollection
+    public boolean remove(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext()) {
+                if (it.next()==null) {
+                    it.remove();
+                    return true;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                if (o.equals(it.next())) {
+                    it.remove();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // copied from AbstractCollection
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<?> it = iterator();
+        while (it.hasNext()) {
+            if (c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    // copied from AbstractCollection
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            if (!c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    public int size() {
+        return base.size();
+    }
+
+    public Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    public Object[] toArray() {
+        return ArraysSupport.reverse(base.toArray());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        return ArraysSupport.toArrayReversed(base, a);
+    }
+
+    public <T> T[] toArray(IntFunction<T[]> generator) {
+        return ArraysSupport.reverse(base.toArray(generator));
+    }
+
+    // copied from AbstractCollection
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    // ========== Deque and Queue ==========
+
+    public void addFirst(E e) {
+        base.addLast(e);
+    }
+
+    public void addLast(E e) {
+        base.addFirst(e);
+    }
+
+    public Iterator<E> descendingIterator() {
+        return base.iterator();
+    }
+
+    public E element() {
+        return base.getLast();
+    }
+
+    public E getFirst() {
+        return base.getLast();
+    }
+
+    public E getLast() {
+        return base.getFirst();
+    }
+
+    public boolean offer(E e) {
+        return base.offerFirst(e);
+    }
+
+    public boolean offerFirst(E e) {
+        return base.offerLast(e);
+    }
+
+    public boolean offerLast(E e) {
+        return base.offerFirst(e);
+    }
+
+    public E peek() {
+        return base.peekLast();
+    }
+
+    public E peekFirst() {
+        return base.peekLast();
+    }
+
+    public E peekLast() {
+        return base.peekFirst();
+    }
+
+    public E poll() {
+        return base.pollLast();
+    }
+
+    public E pollFirst() {
+        return base.pollLast();
+    }
+
+    public E pollLast() {
+        return base.pollFirst();
+    }
+
+    public E pop() {
+        return base.removeLast();
+    }
+
+    public void push(E e) {
+        base.addLast(e);
+    }
+
+    public E remove() {
+        return base.removeLast();
+    }
+
+    public E removeFirst() {
+        return base.removeLast();
+    }
+
+    public E removeLast() {
+        return base.removeFirst();
+    }
+
+    public boolean removeFirstOccurrence(Object o) {
+        return base.removeLastOccurrence(o);
+    }
+
+    public boolean removeLastOccurrence(Object o) {
+        return base.removeFirstOccurrence(o);
+    }
+}
diff --git a/android-35/java/util/ReverseOrderListView.java b/android-35/java/util/ReverseOrderListView.java
new file mode 100644
index 0000000..42b57e2
--- /dev/null
+++ b/android-35/java/util/ReverseOrderListView.java
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * Provides a reverse-ordered view of a List. Not serializable.
+ */
+class ReverseOrderListView<E> implements List<E> {
+
+    final List<E> base;
+    final boolean modifiable;
+
+    public static <T> List<T> of(List<T> list, boolean modifiable) {
+        if (list instanceof ReverseOrderListView<T> rolv) {
+            return rolv.base;
+        } else if (list instanceof RandomAccess) {
+            return new ReverseOrderListView.Rand<>(list, modifiable);
+        } else {
+            return new ReverseOrderListView<>(list, modifiable);
+        }
+    }
+
+    static class Rand<E> extends ReverseOrderListView<E> implements RandomAccess {
+        Rand(List<E> list, boolean modifiable) {
+            super(list, modifiable);
+        }
+    }
+
+    private ReverseOrderListView(List<E> list, boolean modifiable) {
+        this.base = list;
+        this.modifiable = modifiable;
+    }
+
+    /**
+     * Throws if this list is unmodifiable. This should be called from every mutator
+     * method. For bulk ops (addAll, removeAll, etc.) this throws unconditionally.
+     * In contrast, if the base list inherits a bulk op implementation from AbstractList,
+     * it might not throw if no actual mutation would be attempted (e.g., addAll on an
+     * empty collection). Arguably calling this is unnecessary for individual ops,
+     * for which the base list should always throw, but it's easier to verify the right
+     * behavior if every mutator of this class always checks.
+     */
+    void checkModifiable() {
+        if (! modifiable) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    class DescendingIterator implements Iterator<E> {
+        final ListIterator<E> it = base.listIterator(base.size());
+        public boolean hasNext() { return it.hasPrevious(); }
+        public E next() { return it.previous(); }
+        public void remove() {
+            checkModifiable();
+            it.remove();
+            // TODO - make sure ListIterator is positioned correctly afterward
+        }
+    }
+
+    class DescendingListIterator implements ListIterator<E> {
+        final ListIterator<E> it;
+
+        DescendingListIterator(int size, int pos) {
+            if (pos < 0 || pos > size)
+                throw new IndexOutOfBoundsException();
+            it = base.listIterator(size - pos);
+        }
+
+        public boolean hasNext() {
+            return it.hasPrevious();
+        }
+
+        public E next() {
+            return it.previous();
+        }
+
+        public boolean hasPrevious() {
+            return it.hasNext();
+        }
+
+        public E previous() {
+            return it.next();
+        }
+
+        public int nextIndex() {
+            return base.size() - it.nextIndex();
+        }
+
+        public int previousIndex() {
+            return nextIndex() - 1;
+        }
+
+        public void remove() {
+            checkModifiable();
+            it.remove();
+        }
+
+        public void set(E e) {
+            checkModifiable();
+            it.set(e);
+        }
+
+        public void add(E e) {
+            checkModifiable();
+            it.add(e);
+            it.previous();
+        }
+    }
+
+    // ========== Iterable ==========
+
+    public void forEach(Consumer<? super E> action) {
+        for (E e : this)
+            action.accept(e);
+    }
+
+    public Iterator<E> iterator() {
+        return new DescendingIterator();
+    }
+
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.ORDERED);
+    }
+
+    // ========== Collection ==========
+
+    public boolean add(E e) {
+        checkModifiable();
+        base.add(0, e);
+        return true;
+    }
+
+    public boolean addAll(Collection<? extends E> c) {
+        checkModifiable();
+
+        @SuppressWarnings("unchecked")
+        E[] adds = (E[]) c.toArray();
+        if (adds.length == 0) {
+            return false;
+        } else {
+            base.addAll(0, Arrays.asList(ArraysSupport.reverse(adds)));
+            return true;
+        }
+    }
+
+    public void clear() {
+        checkModifiable();
+        base.clear();
+    }
+
+    public boolean contains(Object o) {
+        return base.contains(o);
+    }
+
+    public boolean containsAll(Collection<?> c) {
+        return base.containsAll(c);
+    }
+
+    // copied from AbstractList
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        ListIterator<E> e1 = listIterator();
+        ListIterator<?> e2 = ((List<?>) o).listIterator();
+        while (e1.hasNext() && e2.hasNext()) {
+            E o1 = e1.next();
+            Object o2 = e2.next();
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+        return !(e1.hasNext() || e2.hasNext());
+    }
+
+    // copied from AbstractList
+    public int hashCode() {
+        int hashCode = 1;
+        for (E e : this)
+            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+        return hashCode;
+    }
+
+    public boolean isEmpty() {
+        return base.isEmpty();
+    }
+
+    public Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+
+    // copied from AbstractCollection
+    public boolean remove(Object o) {
+        checkModifiable();
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext()) {
+                if (it.next()==null) {
+                    it.remove();
+                    return true;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                if (o.equals(it.next())) {
+                    it.remove();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // copied from AbstractCollection
+    public boolean removeAll(Collection<?> c) {
+        checkModifiable();
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<?> it = iterator();
+        while (it.hasNext()) {
+            if (c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    // copied from AbstractCollection
+    public boolean retainAll(Collection<?> c) {
+        checkModifiable();
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            if (!c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    public int size() {
+        return base.size();
+    }
+
+    public Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    public Object[] toArray() {
+        return ArraysSupport.reverse(base.toArray());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        return ArraysSupport.toArrayReversed(base, a);
+    }
+
+    public <T> T[] toArray(IntFunction<T[]> generator) {
+        return ArraysSupport.reverse(base.toArray(generator));
+    }
+
+    // copied from AbstractCollection
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    // ========== List ==========
+
+    public void add(int index, E element) {
+        checkModifiable();
+        int size = base.size();
+        checkClosedRange(index, size);
+        base.add(size - index, element);
+    }
+
+    public boolean addAll(int index, Collection<? extends E> c) {
+        checkModifiable();
+        int size = base.size();
+        checkClosedRange(index, size);
+        @SuppressWarnings("unchecked")
+        E[] adds = (E[]) c.toArray();
+        if (adds.length == 0) {
+            return false;
+        } else {
+            base.addAll(size - index, Arrays.asList(ArraysSupport.reverse(adds)));
+            return true;
+        }
+    }
+
+    public E get(int i) {
+        int size = base.size();
+        Objects.checkIndex(i, size);
+        return base.get(size - i - 1);
+    }
+
+    public int indexOf(Object o) {
+        int i = base.lastIndexOf(o);
+        return i == -1 ? -1 : base.size() - i - 1;
+    }
+
+    public int lastIndexOf(Object o) {
+        int i = base.indexOf(o);
+        return i == -1 ? -1 : base.size() - i - 1;
+    }
+
+    public ListIterator<E> listIterator() {
+        return new DescendingListIterator(base.size(), 0);
+    }
+
+    public ListIterator<E> listIterator(int index) {
+        int size = base.size();
+        checkClosedRange(index, size);
+        return new DescendingListIterator(size, index);
+    }
+
+    public E remove(int index) {
+        checkModifiable();
+        int size = base.size();
+        Objects.checkIndex(index, size);
+        return base.remove(size - index - 1);
+    }
+
+    public boolean removeIf(Predicate<? super E> filter) {
+        checkModifiable();
+        return base.removeIf(filter);
+    }
+
+    public void replaceAll(UnaryOperator<E> operator) {
+        checkModifiable();
+        base.replaceAll(operator);
+    }
+
+    public void sort(Comparator<? super E> c) {
+        checkModifiable();
+        base.sort(Collections.reverseOrder(c));
+    }
+
+    public E set(int index, E element) {
+        checkModifiable();
+        int size = base.size();
+        Objects.checkIndex(index, size);
+        return base.set(size - index - 1, element);
+    }
+
+    public List<E> subList(int fromIndex, int toIndex) {
+        int size = base.size();
+        Objects.checkFromToIndex(fromIndex, toIndex, size);
+        return new ReverseOrderListView<>(base.subList(size - toIndex, size - fromIndex), modifiable);
+    }
+
+    static void checkClosedRange(int index, int size) {
+        if (index < 0 || index > size) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+        }
+    }
+}
diff --git a/android-35/java/util/ReverseOrderSortedMapView.java b/android-35/java/util/ReverseOrderSortedMapView.java
new file mode 100644
index 0000000..404950e
--- /dev/null
+++ b/android-35/java/util/ReverseOrderSortedMapView.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Provides a reversed-ordered view of a SortedMap. Not serializable.
+ *
+ * TODO: copy in equals and hashCode from AbstractMap
+ */
+class ReverseOrderSortedMapView<K, V> extends AbstractMap<K, V> implements SortedMap<K, V> {
+    final SortedMap<K, V> base;
+    final Comparator<? super K> cmp;
+
+    private ReverseOrderSortedMapView(SortedMap<K, V> map) {
+        base = map;
+        cmp = Collections.reverseOrder(map.comparator());
+    }
+
+    public static <K, V> SortedMap<K, V> of(SortedMap<K, V> map) {
+        if (map instanceof ReverseOrderSortedMapView<K, V> rosmv) {
+            return rosmv.base;
+        } else {
+            return new ReverseOrderSortedMapView<>(map);
+        }
+    }
+
+    // ========== Object ==========
+
+    // equals: inherited from AbstractMap
+
+    // hashCode: inherited from AbstractMap
+
+    public String toString() {
+        return toString(this, descendingEntryIterator(base));
+    }
+
+    // ========== Map ==========
+
+    public void clear() {
+        base.clear();
+    }
+
+    public boolean containsKey(Object key) {
+        return base.containsKey(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return base.containsValue(value);
+    }
+
+    public V get(Object key) {
+        return base.get(key);
+    }
+
+    public boolean isEmpty() {
+        return base.isEmpty();
+    }
+
+    public V put(K key, V value) {
+        return base.put(key, value);
+    }
+
+    public void putAll(Map<? extends K, ? extends V> m) {
+        base.putAll(m);
+    }
+
+    public V remove(Object key) {
+        return base.remove(key);
+    }
+
+    public int size() {
+        return base.size();
+    }
+
+    public Set<K> keySet() {
+        return new AbstractSet<>() {
+            // inherit add(), which throws UOE
+            public Iterator<K> iterator() { return descendingKeyIterator(base); }
+            public int size() { return base.size(); }
+            public void clear() { base.keySet().clear(); }
+            public boolean contains(Object o) { return base.keySet().contains(o); }
+            public boolean remove(Object o) { return base.keySet().remove(o); }
+        };
+    }
+
+    public Collection<V> values() {
+        return new AbstractCollection<>() {
+            // inherit add(), which throws UOE
+            public Iterator<V> iterator() { return descendingValueIterator(base); }
+            public int size() { return base.size(); }
+            public void clear() { base.values().clear(); }
+            public boolean contains(Object o) { return base.values().contains(o); }
+            public boolean remove(Object o) { return base.values().remove(o); }
+        };
+    }
+
+    public Set<Entry<K, V>> entrySet() {
+        return new AbstractSet<>() {
+            // inherit add(), which throws UOE
+            public Iterator<Entry<K, V>> iterator() { return descendingEntryIterator(base); }
+            public int size() { return base.size(); }
+            public void clear() { base.entrySet().clear(); }
+            public boolean contains(Object o) { return base.entrySet().contains(o); }
+            public boolean remove(Object o) { return base.entrySet().remove(o); }
+        };
+    }
+
+    // ========== SequencedMap ==========
+
+    public SortedMap<K, V> reversed() {
+        return base;
+    }
+
+    public K firstKey() {
+        return base.lastKey();
+    }
+
+    public K lastKey() {
+        return base.firstKey();
+    }
+
+    public Map.Entry<K, V> firstEntry() {
+        return base.lastEntry();
+    }
+
+    public Map.Entry<K, V> lastEntry() {
+        return base.firstEntry();
+    }
+
+    public Map.Entry<K,V> pollFirstEntry() {
+        return base.pollLastEntry();
+    }
+
+    public Map.Entry<K,V> pollLastEntry() {
+        return base.pollFirstEntry();
+    }
+
+    public V putFirst(K k, V v) {
+        return base.putLast(k, v);
+    }
+
+    public V putLast(K k, V v) {
+        return base.putFirst(k, v);
+    }
+
+    // ========== SortedMap ==========
+
+    public Comparator<? super K> comparator() {
+        return cmp;
+    }
+
+    public SortedMap<K, V> subMap(K fromKey, K toKey) {
+        if (cmp.compare(fromKey, toKey) <= 0) {
+            return new Submap(fromKey, toKey);
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    public SortedMap<K, V> headMap(K toKey) {
+        return new Submap(null, toKey);
+    }
+
+    public SortedMap<K, V> tailMap(K fromKey) {
+        return new Submap(fromKey, null);
+    }
+
+    // ========== Infrastructure ==========
+
+    static <K, V> Iterator<K> descendingKeyIterator(SortedMap<K, V> map) {
+        return new Iterator<>() {
+            SortedMap<K, V> root = map;
+            SortedMap<K, V> view = map;
+            K prev = null;
+
+            public boolean hasNext() {
+                return ! view.isEmpty();
+            }
+
+            public K next() {
+                if (view.isEmpty())
+                    throw new NoSuchElementException();
+                K k = prev = view.lastKey();
+                view = root.headMap(k);
+                return k;
+            }
+
+            public void remove() {
+                if (prev == null) {
+                    throw new IllegalStateException();
+                } else {
+                    root.remove(prev);
+                    prev = null;
+                }
+            }
+        };
+    }
+
+    static <K, V> Iterator<V> descendingValueIterator(SortedMap<K, V> map) {
+        return new Iterator<>() {
+            Iterator<K> keyIterator = descendingKeyIterator(map);
+
+            public boolean hasNext() {
+                return keyIterator.hasNext();
+            }
+
+            public V next() {
+                return map.get(keyIterator.next());
+            }
+
+            public void remove() {
+                keyIterator.remove();
+            }
+        };
+    }
+
+    static <K, V> Iterator<Map.Entry<K, V>> descendingEntryIterator(SortedMap<K, V> map) {
+        return new Iterator<>() {
+            Iterator<K> keyIterator = descendingKeyIterator(map);
+
+            public boolean hasNext() {
+                return keyIterator.hasNext();
+            }
+
+            public Map.Entry<K, V> next() {
+                K key = keyIterator.next();
+                return new ViewEntry<>(map, key, map.get(key));
+            }
+
+            public void remove() {
+                keyIterator.remove();
+            }
+        };
+    }
+
+    static class ViewEntry<K, V> implements Map.Entry<K, V> {
+        final Map<K, V> map;
+        final K key;
+        final V value;
+
+        ViewEntry(Map<K, V> map, K key, V value) {
+            this.map = map;
+            this.key = key;
+            this.value = value;
+        }
+
+        public K getKey()             { return key; }
+        public V getValue()           { return value; }
+        public V setValue(V newValue) { return map.put(key, newValue); }
+
+        public boolean equals(Object o) {
+            return o instanceof Map.Entry<?, ?> e
+                    && Objects.equals(key, e.getKey())
+                    && Objects.equals(value, e.getValue());
+        }
+
+        public int hashCode() {
+            return Objects.hashCode(key) ^ Objects.hashCode(value);
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    // copied and modified from AbstractMap
+    static <K, V> String toString(Map<K, V> thisMap, Iterator<Entry<K,V>> i) {
+        if (! i.hasNext())
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (;;) {
+            Entry<K,V> e = i.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == thisMap ? "(this Map)" : key);
+            sb.append('=');
+            sb.append(value == thisMap ? "(this Map)" : value);
+            if (! i.hasNext())
+                return sb.append('}').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Used for various submap views. We can't use the base SortedMap's subMap,
+     * because of the asymmetry between from-inclusive and to-exclusive.
+     */
+    class Submap extends AbstractMap<K, V> implements SortedMap<K, V> {
+        final K head; // head key, or negative infinity if null
+        final K tail; // tail key, or positive infinity if null
+
+        @SuppressWarnings("unchecked")
+        Submap(K head, K tail) {
+            this.head = head;
+            this.tail = tail;
+        }
+
+        // returns whether e is above the head, inclusive
+        boolean aboveHead(K k) {
+            return head == null || cmp.compare(k, head) >= 0;
+        }
+
+        // returns whether e is below the tail, exclusive
+        boolean belowTail(K k) {
+            return tail == null || cmp.compare(k, tail) < 0;
+        }
+
+        Iterator<Entry<K, V>> entryIterator() {
+            return new Iterator<>() {
+                Entry<K, V> cache = null;
+                K prevKey = null;
+                boolean dead = false;
+                Iterator<Entry<K, V>> it = descendingEntryIterator(base);
+
+                public boolean hasNext() {
+                    if (dead)
+                        return false;
+
+                    if (cache != null)
+                        return true;
+
+                    while (it.hasNext()) {
+                        Entry<K, V> e = it.next();
+
+                        if (! aboveHead(e.getKey()))
+                            continue;
+
+                        if (! belowTail(e.getKey())) {
+                            dead = true;
+                            return false;
+                        }
+
+                        cache = e;
+                        return true;
+                    }
+
+                    return false;
+                }
+
+                public Entry<K, V> next() {
+                    if (hasNext()) {
+                        Entry<K, V> e = cache;
+                        cache = null;
+                        prevKey = e.getKey();
+                        return e;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+
+                public void remove() {
+                    if (prevKey == null) {
+                        throw new IllegalStateException();
+                    } else {
+                        base.remove(prevKey);
+                    }
+                }
+            };
+        }
+
+        // equals: inherited from AbstractMap
+
+        // hashCode: inherited from AbstractMap
+
+        public String toString() {
+            return ReverseOrderSortedMapView.toString(this, entryIterator());
+        }
+
+        public Set<Entry<K, V>> entrySet() {
+            return new AbstractSet<>() {
+                public Iterator<Entry<K, V>> iterator() {
+                    return entryIterator();
+                }
+
+                public int size() {
+                    int sz = 0;
+                    for (var it = entryIterator(); it.hasNext();) {
+                        it.next();
+                        sz++;
+                    }
+                    return sz;
+                }
+            };
+        }
+
+        public V put(K key, V value) {
+            if (aboveHead(key) && belowTail(key))
+                return base.put(key, value);
+            else
+                throw new IllegalArgumentException();
+        }
+
+        public V remove(Object o) {
+            @SuppressWarnings("unchecked")
+            K key = (K) o;
+            if (aboveHead(key) && belowTail(key))
+                return base.remove(o);
+            else
+                return null;
+        }
+
+        public int size() {
+            return entrySet().size();
+        }
+
+        public Comparator<? super K> comparator() {
+            return cmp;
+        }
+
+        public K firstKey() {
+            return this.entryIterator().next().getKey();
+        }
+
+        public K lastKey() {
+            var it = this.entryIterator();
+            if (! it.hasNext())
+                throw new NoSuchElementException();
+            var last = it.next();
+            while (it.hasNext())
+                last = it.next();
+            return last.getKey();
+        }
+
+        public SortedMap<K, V> subMap(K from, K to) {
+            if (aboveHead(from) && belowTail(from) &&
+                aboveHead(to) && belowTail(to) &&
+                cmp.compare(from, to) <= 0) {
+                return new Submap(from, to);
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        public SortedMap<K, V> headMap(K to) {
+            if (aboveHead(to) && belowTail(to))
+                return new Submap(head, to);
+            else
+                throw new IllegalArgumentException();
+        }
+
+        public SortedMap<K, V> tailMap(K from) {
+            if (aboveHead(from) && belowTail(from))
+                return new Submap(from, tail);
+            else
+                throw new IllegalArgumentException();
+        }
+    }
+}
diff --git a/android-35/java/util/ReverseOrderSortedSetView.java b/android-35/java/util/ReverseOrderSortedSetView.java
new file mode 100644
index 0000000..3719852
--- /dev/null
+++ b/android-35/java/util/ReverseOrderSortedSetView.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * Provides a reversed-ordered view of a SortedSet. Not serializable.
+ */
+class ReverseOrderSortedSetView<E> implements SortedSet<E> {
+    final SortedSet<E> base;
+    final Comparator<? super E> comp;
+
+    private ReverseOrderSortedSetView(SortedSet<E> set) {
+        base = set;
+        comp = Collections.reverseOrder(set.comparator());
+    }
+
+    public static <T> SortedSet<T> of(SortedSet<T> set) {
+        if (set instanceof ReverseOrderSortedSetView<T> rossv) {
+            return rossv.base;
+        } else {
+            return new ReverseOrderSortedSetView<>(set);
+        }
+    }
+
+    // ========== Object ==========
+
+    // copied from AbstractSet
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        if (c.size() != size())
+            return false;
+        try {
+            return containsAll(c);
+        } catch (ClassCastException | NullPointerException unused) {
+            return false;
+        }
+    }
+
+    // copied from AbstractSet
+    public int hashCode() {
+        int h = 0;
+        Iterator<E> i = iterator();
+        while (i.hasNext()) {
+            E obj = i.next();
+            if (obj != null)
+                h += obj.hashCode();
+        }
+        return h;
+    }
+
+    // copied from AbstractCollection
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    // ========== Iterable ==========
+
+    public void forEach(Consumer<? super E> action) {
+        for (E e : this)
+            action.accept(e);
+    }
+
+    public Iterator<E> iterator() {
+        return descendingIterator(base);
+    }
+
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.ORDERED);
+    }
+
+    // ========== Collection ==========
+
+    public boolean add(E e) {
+        base.add(e);
+        return true;
+    }
+
+    public boolean addAll(Collection<? extends E> c) {
+        return base.addAll(c);
+    }
+
+    public void clear() {
+        base.clear();
+    }
+
+    public boolean contains(Object o) {
+        return base.contains(o);
+    }
+
+    public boolean containsAll(Collection<?> c) {
+        return base.containsAll(c);
+    }
+
+    public boolean isEmpty() {
+        return base.isEmpty();
+    }
+
+    public Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+
+    public boolean remove(Object o) {
+        return base.remove(o);
+    }
+
+    public boolean removeAll(Collection<?> c) {
+        return base.removeAll(c);
+    }
+
+    // copied from AbstractCollection
+    public boolean retainAll(Collection<?> c) {
+        return base.retainAll(c);
+    }
+
+    public int size() {
+        return base.size();
+    }
+
+    public Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    public Object[] toArray() {
+        return ArraysSupport.reverse(base.toArray());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        return ArraysSupport.toArrayReversed(base, a);
+    }
+
+    public <T> T[] toArray(IntFunction<T[]> generator) {
+        return ArraysSupport.reverse(base.toArray(generator));
+    }
+
+    // ========== SortedSet ==========
+
+    public Comparator<? super E> comparator() {
+        return comp;
+    }
+
+    public E first() { return base.last(); }
+
+    public E last() { return base.first(); }
+
+    public SortedSet<E> headSet(E to) {
+        return new Subset(null, to);
+    }
+
+    public SortedSet<E> subSet(E from, E to) {
+        return new Subset(from, to);
+    }
+
+    public SortedSet<E> tailSet(E from) {
+        return new Subset(from, null);
+    }
+
+    // ========== Infrastructure ==========
+
+    static <T> Iterator<T> descendingIterator(SortedSet<T> set) {
+        return new Iterator<>() {
+            SortedSet<T> root = set;
+            SortedSet<T> view = set;
+            T prev = null;
+
+            public boolean hasNext() {
+                return ! view.isEmpty();
+            }
+
+            public T next() {
+                if (view.isEmpty())
+                    throw new NoSuchElementException();
+                T t = prev = view.last();
+                view = root.headSet(t);
+                return t;
+            }
+
+            public void remove() {
+                if (prev == null) {
+                    throw new IllegalStateException();
+                } else {
+                    root.remove(prev);
+                    prev = null;
+                }
+            }
+        };
+    }
+
+    /**
+     * Used for various subset views. We can't use the base SortedSet's subset,
+     * because of the asymmetry between from-inclusive and to-exclusive.
+     */
+    class Subset extends AbstractSet<E> implements SortedSet<E> {
+        final E head; // head element, or negative infinity if null
+        final E tail; // tail element, or positive infinity if null
+        final Comparator<E> cmp;
+
+        @SuppressWarnings("unchecked")
+        Subset(E head, E tail) {
+            this.head = head;
+            this.tail = tail;
+            Comparator<E> c = (Comparator<E>) ReverseOrderSortedSetView.this.comparator();
+            if (c == null)
+                c = (Comparator<E>) Comparator.naturalOrder();
+            cmp = c;
+        }
+
+        // returns whether e is above the head, inclusive
+        boolean aboveHead(E e) {
+            return head == null || cmp.compare(e, head) >= 0;
+        }
+
+        // returns whether e is below the tail, exclusive
+        boolean belowTail(E e) {
+            return tail == null || cmp.compare(e, tail) < 0;
+        }
+
+        public Iterator<E> iterator() {
+            return new Iterator<>() {
+                E cache = null;
+                boolean dead = false;
+                Iterator<E> it = descendingIterator(base);
+
+                public boolean hasNext() {
+                    if (dead)
+                        return false;
+
+                    if (cache != null)
+                        return true;
+
+                    while (it.hasNext()) {
+                        E e = it.next();
+
+                        if (! aboveHead(e))
+                            continue;
+
+                        if (! belowTail(e)) {
+                            dead = true;
+                            return false;
+                        }
+
+                        cache = e;
+                        return true;
+                    }
+
+                    return false;
+                }
+
+                public E next() {
+                    if (hasNext()) {
+                        E e = cache;
+                        cache = null;
+                        return e;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        public boolean add(E e) {
+            if (aboveHead(e) && belowTail(e))
+                return base.add(e);
+            else
+                throw new IllegalArgumentException();
+        }
+
+        public boolean remove(Object o) {
+            @SuppressWarnings("unchecked")
+            E e = (E) o;
+            if (aboveHead(e) && belowTail(e))
+                return base.remove(o);
+            else
+                return false;
+        }
+
+        public int size() {
+            int sz = 0;
+            for (E e : this)
+                sz++;
+            return sz;
+        }
+
+        public Comparator<? super E> comparator() {
+            return ReverseOrderSortedSetView.this.comparator();
+        }
+
+        public E first() {
+            return this.iterator().next();
+        }
+
+        public E last() {
+            var it = this.iterator();
+            if (! it.hasNext())
+                throw new NoSuchElementException();
+            E last = it.next();
+            while (it.hasNext())
+                last = it.next();
+            return last;
+        }
+
+        public SortedSet<E> subSet(E from, E to) {
+            if (aboveHead(from) && belowTail(from) &&
+                aboveHead(to) && belowTail(to) &&
+                cmp.compare(from, to) <= 0) {
+                return ReverseOrderSortedSetView.this.new Subset(from, to);
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        public SortedSet<E> headSet(E to) {
+            if (aboveHead(to) && belowTail(to))
+                return ReverseOrderSortedSetView.this.new Subset(head, to);
+            else
+                throw new IllegalArgumentException();
+        }
+
+        public SortedSet<E> tailSet(E from) {
+            if (aboveHead(from) && belowTail(from))
+                return ReverseOrderSortedSetView.this.new Subset(null, tail);
+            else
+                throw new IllegalArgumentException();
+        }
+
+    }
+}
diff --git a/android-35/java/util/Scanner.java b/android-35/java/util/Scanner.java
new file mode 100644
index 0000000..7471c3b
--- /dev/null
+++ b/android-35/java/util/Scanner.java
@@ -0,0 +1,3074 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.math.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.charset.*;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.text.*;
+import java.util.function.Consumer;
+import java.util.regex.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A simple text scanner which can parse primitive types and strings using
+ * regular expressions.
+ *
+ * <p>A {@code Scanner} breaks its input into tokens using a
+ * delimiter pattern, which by default matches whitespace. The resulting
+ * tokens may then be converted into values of different types using the
+ * various {@code next} methods.
+ *
+ * <p>For example, this code allows a user to read a number from
+ * {@code System.in}:
+ * <blockquote><pre>{@code
+ *     Scanner sc = new Scanner(System.in);
+ *     int i = sc.nextInt();
+ * }</pre></blockquote>
+ *
+ * <p>As another example, this code allows {@code long} types to be
+ * assigned from entries in a file {@code myNumbers}:
+ * <blockquote><pre>{@code
+ *      Scanner sc = new Scanner(new File("myNumbers"));
+ *      while (sc.hasNextLong()) {
+ *          long aLong = sc.nextLong();
+ *      }
+ * }</pre></blockquote>
+ *
+ * <p>The scanner can also use delimiters other than whitespace. This
+ * example reads several items in from a string:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.next());
+ *     System.out.println(s.next());
+ *     s.close();
+ * }</pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>{@code
+ *     1
+ *     2
+ *     red
+ *     blue
+ * }</pre></blockquote>
+ *
+ * <p>The same output can be generated with this code, which uses a regular
+ * expression to parse all four tokens at once:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input);
+ *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
+ *     MatchResult result = s.match();
+ *     for (int i=1; i<=result.groupCount(); i++)
+ *         System.out.println(result.group(i));
+ *     s.close();
+ * }</pre></blockquote>
+ *
+ * <p>The <a id="default-delimiter">default whitespace delimiter</a> used
+ * by a scanner is as recognized by {@link Character#isWhitespace(char)
+ * Character.isWhitespace()}. The {@link #reset reset()}
+ * method will reset the value of the scanner's delimiter to the default
+ * whitespace delimiter regardless of whether it was previously changed.
+ *
+ * <p>A scanning operation may block waiting for input.
+ *
+ * <p>The {@link #next} and {@link #hasNext} methods and their
+ * companion methods (such as {@link #nextInt} and
+ * {@link #hasNextInt}) first skip any input that matches the delimiter
+ * pattern, and then attempt to return the next token. Both {@code hasNext()}
+ * and {@code next()} methods may block waiting for further input.  Whether a
+ * {@code hasNext()} method blocks has no connection to whether or not its
+ * associated {@code next()} method will block. The {@link #tokens} method
+ * may also block waiting for input.
+ *
+ * <p>The {@link #findInLine findInLine()},
+ * {@link #findWithinHorizon findWithinHorizon()},
+ * {@link #skip skip()}, and {@link #findAll findAll()}
+ * methods operate independently of the delimiter pattern. These methods will
+ * attempt to match the specified pattern with no regard to delimiters in the
+ * input and thus can be used in special circumstances where delimiters are
+ * not relevant. These methods may block waiting for more input.
+ *
+ * <p>When a scanner throws an {@link InputMismatchException}, the scanner
+ * will not pass the token that caused the exception, so that it may be
+ * retrieved or skipped via some other method.
+ *
+ * <p>Depending upon the type of delimiting pattern, empty tokens may be
+ * returned. For example, the pattern {@code "\\s+"} will return no empty
+ * tokens since it matches multiple instances of the delimiter. The delimiting
+ * pattern {@code "\\s"} could return empty tokens since it only passes one
+ * space at a time.
+ *
+ * <p> A scanner can read text from any object which implements the {@link
+ * java.lang.Readable} interface.  If an invocation of the underlying
+ * readable's {@link java.lang.Readable#read read()} method throws an {@link
+ * java.io.IOException} then the scanner assumes that the end of the input
+ * has been reached.  The most recent {@code IOException} thrown by the
+ * underlying readable can be retrieved via the {@link #ioException} method.
+ *
+ * <p>When a {@code Scanner} is closed, it will close its input source
+ * if the source implements the {@link java.io.Closeable} interface.
+ *
+ * <p>A {@code Scanner} is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * <p>Unless otherwise mentioned, passing a {@code null} parameter into
+ * any method of a {@code Scanner} will cause a
+ * {@code NullPointerException} to be thrown.
+ *
+ * <p>A scanner will default to interpreting numbers as decimal unless a
+ * different radix has been set by using the {@link #useRadix} method. The
+ * {@link #reset} method will reset the value of the scanner's radix to
+ * {@code 10} regardless of whether it was previously changed.
+ *
+ * <h2> <a id="localized-numbers">Localized numbers</a> </h2>
+ *
+ * <p> An instance of this class is capable of scanning numbers in the standard
+ * formats as well as in the formats of the scanner's locale. A scanner's
+ * <a id="initial-locale">initial locale </a>is the value returned by the {@link
+ * java.util.Locale#getDefault(Locale.Category)
+ * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
+ * #useLocale useLocale()} method. The {@link #reset} method will reset the value of the
+ * scanner's locale to the initial locale regardless of whether it was
+ * previously changed.
+ *
+ * <p>The localized formats are defined in terms of the following parameters,
+ * which for a particular locale are taken from that locale's {@link
+ * java.text.DecimalFormat DecimalFormat} object, {@code df}, and its and
+ * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
+ * {@code dfs}.
+ *
+ * <blockquote><dl>
+ *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used to separate thousands groups,
+ *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
+ *         java.text.DecimalFormatSymbols#getGroupingSeparator
+ *         getGroupingSeparator()}
+ *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used for the decimal point,
+ *     <i>i.e.,</i>&nbsp;{@code dfs.}{@link
+ *     java.text.DecimalFormatSymbols#getDecimalSeparator
+ *     getDecimalSeparator()}
+ *     <dt><i>LocalPositivePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a positive number (may
+ *         be empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
+ *         java.text.DecimalFormat#getPositivePrefix
+ *         getPositivePrefix()}
+ *     <dt><i>LocalPositiveSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a positive number (may be
+ *         empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
+ *         java.text.DecimalFormat#getPositiveSuffix
+ *         getPositiveSuffix()}
+ *     <dt><i>LocalNegativePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a negative number (may
+ *         be empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
+ *         java.text.DecimalFormat#getNegativePrefix
+ *         getNegativePrefix()}
+ *     <dt><i>LocalNegativeSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a negative number (may be
+ *         empty), <i>i.e.,</i>&nbsp;{@code df.}{@link
+ *     java.text.DecimalFormat#getNegativeSuffix
+ *     getNegativeSuffix()}
+ *     <dt><i>LocalNaN&nbsp;&nbsp;</i>
+ *         <dd>The string that represents not-a-number for
+ *         floating-point values,
+ *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
+ *         java.text.DecimalFormatSymbols#getNaN
+ *         getNaN()}
+ *     <dt><i>LocalInfinity&nbsp;&nbsp;</i>
+ *         <dd>The string that represents infinity for floating-point
+ *         values, <i>i.e.,</i>&nbsp;{@code dfs.}{@link
+ *         java.text.DecimalFormatSymbols#getInfinity
+ *         getInfinity()}
+ * </dl></blockquote>
+ *
+ * <h3> <a id="number-syntax">Number syntax</a> </h3>
+ *
+ * <p> The strings that can be parsed as numbers by an instance of this class
+ * are specified in terms of the following regular-expression grammar, where
+ * Rmax is the highest digit in the radix being used (for example, Rmax is 9 in base 10).
+ *
+ * <dl>
+ *   <dt><i>NonAsciiDigit</i>:
+ *       <dd>A non-ASCII character c for which
+ *            {@link java.lang.Character#isDigit Character.isDigit}{@code (c)}
+ *                        returns&nbsp;true
+ *
+ *   <dt><i>Non0Digit</i>:
+ *       <dd>{@code [1-}<i>Rmax</i>{@code ] | }<i>NonASCIIDigit</i>
+ *
+ *   <dt><i>Digit</i>:
+ *       <dd>{@code [0-}<i>Rmax</i>{@code ] | }<i>NonASCIIDigit</i>
+ *
+ *   <dt><i>GroupedNumeral</i>:
+ *       <dd><code>(&nbsp;</code><i>Non0Digit</i>
+ *                   <i>Digit</i>{@code ?
+ *                   }<i>Digit</i>{@code ?}
+ *       <dd>&nbsp;&nbsp;&nbsp;&nbsp;<code>(&nbsp;</code><i>LocalGroupSeparator</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i>{@code  )+ )}
+ *
+ *   <dt><i>Numeral</i>:
+ *       <dd>{@code ( ( }<i>Digit</i>{@code + )
+ *               | }<i>GroupedNumeral</i>{@code  )}
+ *
+ *   <dt><a id="Integer-regex"><i>Integer</i>:</a>
+ *       <dd>{@code ( [-+]? ( }<i>Numeral</i>{@code
+ *                               ) )}
+ *       <dd>{@code | }<i>LocalPositivePrefix</i> <i>Numeral</i>
+ *                      <i>LocalPositiveSuffix</i>
+ *       <dd>{@code | }<i>LocalNegativePrefix</i> <i>Numeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><i>DecimalNumeral</i>:
+ *       <dd><i>Numeral</i>
+ *       <dd>{@code | }<i>Numeral</i>
+ *                 <i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i>{@code *}
+ *       <dd>{@code | }<i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i>{@code +}
+ *
+ *   <dt><i>Exponent</i>:
+ *       <dd>{@code ( [eE] [+-]? }<i>Digit</i>{@code + )}
+ *
+ *   <dt><a id="Decimal-regex"><i>Decimal</i>:</a>
+ *       <dd>{@code ( [-+]? }<i>DecimalNumeral</i>
+ *                         <i>Exponent</i>{@code ? )}
+ *       <dd>{@code | }<i>LocalPositivePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *                 <i>Exponent</i>{@code ?}
+ *       <dd>{@code | }<i>LocalNegativePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *                 <i>Exponent</i>{@code ?}
+ *
+ *   <dt><i>HexFloat</i>:
+ *       <dd>{@code [-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+
+ *                 ([pP][-+]?[0-9]+)?}
+ *
+ *   <dt><i>NonNumber</i>:
+ *       <dd>{@code NaN
+ *                          | }<i>LocalNan</i>{@code
+ *                          | Infinity
+ *                          | }<i>LocalInfinity</i>
+ *
+ *   <dt><i>SignedNonNumber</i>:
+ *       <dd>{@code ( [-+]? }<i>NonNumber</i>{@code  )}
+ *       <dd>{@code | }<i>LocalPositivePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *       <dd>{@code | }<i>LocalNegativePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><a id="Float-regex"><i>Float</i></a>:
+ *       <dd><i>Decimal</i>
+ *           {@code | }<i>HexFloat</i>
+ *           {@code | }<i>SignedNonNumber</i>
+ *
+ * </dl>
+ * <p>Whitespace is not significant in the above regular expressions.
+ *
+ * @since   1.5
+ */
+public final class Scanner implements Iterator<String>, Closeable {
+
+    // Internal buffer used to hold input
+    private CharBuffer buf;
+
+    // Size of internal character buffer
+    private static final int BUFFER_SIZE = 1024; // change to 1024;
+
+    // The index into the buffer currently held by the Scanner
+    private int position;
+
+    // Internal matcher used for finding delimiters
+    private Matcher matcher;
+
+    // Pattern used to delimit tokens
+    private Pattern delimPattern;
+
+    // Pattern found in last hasNext operation
+    private Pattern hasNextPattern;
+
+    // Position after last hasNext operation
+    private int hasNextPosition;
+
+    // Result after last hasNext operation
+    private String hasNextResult;
+
+    // The input source
+    private Readable source;
+
+    // Boolean is true if source is done
+    private boolean sourceClosed = false;
+
+    // Boolean indicating more input is required
+    private boolean needInput = false;
+
+    // Boolean indicating if a delim has been skipped this operation
+    private boolean skipped = false;
+
+    // A store of a position that the scanner may fall back to
+    private int savedScannerPosition = -1;
+
+    // A cache of the last primitive type scanned
+    private Object typeCache = null;
+
+    // Boolean indicating if a match result is available
+    private boolean matchValid = false;
+
+    // Boolean indicating if this scanner has been closed
+    private boolean closed = false;
+
+    // The current radix used by this scanner
+    private int radix = 10;
+
+    // The default radix for this scanner
+    private int defaultRadix = 10;
+
+    // The locale used by this scanner
+    private Locale locale = null;
+
+    // A cache of the last few recently used Patterns
+    private PatternLRUCache patternCache = new PatternLRUCache(7);
+
+    // A holder of the last IOException encountered
+    private IOException lastException;
+
+    // Number of times this scanner's state has been modified.
+    // Generally incremented on most public APIs and checked
+    // within spliterator implementations.
+    int modCount;
+
+    // A pattern for java whitespace
+    private static Pattern WHITESPACE_PATTERN = Pattern.compile(
+                                                "\\p{javaWhitespace}+");
+
+    // A pattern for any token
+    private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
+
+    // A pattern for non-ASCII digits
+    private static Pattern NON_ASCII_DIGIT = Pattern.compile(
+        "[\\p{javaDigit}&&[^0-9]]");
+
+    // Fields and methods to support scanning primitive types
+
+    /**
+     * Locale dependent values used to scan numbers
+     */
+    private String groupSeparator = "\\,";
+    private String decimalSeparator = "\\.";
+    private String nanString = "NaN";
+    private String infinityString = "Infinity";
+    private String positivePrefix = "";
+    private String negativePrefix = "\\-";
+    private String positiveSuffix = "";
+    private String negativeSuffix = "";
+
+    /**
+     * Fields and an accessor method to match booleans
+     */
+    private static volatile Pattern boolPattern;
+    private static final String BOOLEAN_PATTERN = "true|false";
+    private static Pattern boolPattern() {
+        Pattern bp = boolPattern;
+        if (bp == null)
+            boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
+                                          Pattern.CASE_INSENSITIVE);
+        return bp;
+    }
+
+    /**
+     * Fields and methods to match bytes, shorts, ints, and longs
+     */
+    private Pattern integerPattern;
+    private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+    private String non0Digit = "[\\p{javaDigit}&&[^0]]";
+    private int SIMPLE_GROUP_INDEX = 5;
+    private String buildIntegerPatternString() {
+        String radixDigits = digits.substring(0, radix);
+        // \\p{javaDigit} is not guaranteed to be appropriate
+        // here but what can we do? The final authority will be
+        // whatever parse method is invoked, so ultimately the
+        // Scanner will do the right thing
+        String digit = "((?i)["+radixDigits+"\\p{javaDigit}])";
+        // BEGIN Android-changed: Support non-decimal starting digits.
+        // Ie., in addition to 1-9, a-z are also valid radix digits.
+        /*
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        */
+        String non0RadixDigits = "((?i)[" + digits.substring(1, radix) + "]|(" + non0Digit + "))";
+        String groupedNumeral = "("+non0RadixDigits+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // END Android-changed: Support non-decimal starting digits.
+        // digit++ is the possessive form which is necessary for reducing
+        // backtracking that would otherwise cause unacceptable performance
+        String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
+        String javaStyleInteger = "([-+]?(" + numeral + "))";
+        String negativeInteger = negativePrefix + numeral + negativeSuffix;
+        String positiveInteger = positivePrefix + numeral + positiveSuffix;
+        return "("+ javaStyleInteger + ")|(" +
+            positiveInteger + ")|(" +
+            negativeInteger + ")";
+    }
+    private Pattern integerPattern() {
+        if (integerPattern == null) {
+            integerPattern = patternCache.forName(buildIntegerPatternString());
+        }
+        return integerPattern;
+    }
+
+    /**
+     * Fields and an accessor method to match line separators
+     */
+    private static volatile Pattern separatorPattern;
+    private static volatile Pattern linePattern;
+    private static final String LINE_SEPARATOR_PATTERN =
+                                           "\r\n|[\n\r\u2028\u2029\u0085]";
+    private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";
+
+    private static Pattern separatorPattern() {
+        Pattern sp = separatorPattern;
+        if (sp == null)
+            separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
+        return sp;
+    }
+
+    private static Pattern linePattern() {
+        Pattern lp = linePattern;
+        if (lp == null)
+            linePattern = lp = Pattern.compile(LINE_PATTERN);
+        return lp;
+    }
+
+    /**
+     * Fields and methods to match floats and doubles
+     */
+    private Pattern floatPattern;
+    private Pattern decimalPattern;
+    private void buildFloatAndDecimalPattern() {
+        // \\p{javaDigit} may not be perfect, see above
+        String digit = "(([0-9\\p{javaDigit}]))";
+        String exponent = "([eE][+-]?"+digit+"+)?";
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // Once again digit++ is used for performance, as above
+        String numeral = "(("+digit+"++)|"+groupedNumeral+")";
+        String decimalNumeral = "("+numeral+"|"+numeral +
+            decimalSeparator + digit + "*+|"+ decimalSeparator +
+            digit + "++)";
+        String nonNumber = "(NaN|"+nanString+"|Infinity|"+
+                               infinityString+")";
+        String positiveFloat = "(" + positivePrefix + decimalNumeral +
+                            positiveSuffix + exponent + ")";
+        String negativeFloat = "(" + negativePrefix + decimalNumeral +
+                            negativeSuffix + exponent + ")";
+        String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
+            positiveFloat + "|" + negativeFloat + ")";
+        String hexFloat =
+            "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
+        String positiveNonNumber = "(" + positivePrefix + nonNumber +
+                            positiveSuffix + ")";
+        String negativeNonNumber = "(" + negativePrefix + nonNumber +
+                            negativeSuffix + ")";
+        String signedNonNumber = "(([-+]?"+nonNumber+")|" +
+                                 positiveNonNumber + "|" +
+                                 negativeNonNumber + ")";
+        floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
+                                       signedNonNumber);
+        decimalPattern = Pattern.compile(decimal);
+    }
+    private Pattern floatPattern() {
+        if (floatPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return floatPattern;
+    }
+    private Pattern decimalPattern() {
+        if (decimalPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return decimalPattern;
+    }
+
+    // Constructors
+
+    /**
+     * Constructs a {@code Scanner} that returns values scanned
+     * from the specified source delimited by the specified pattern.
+     *
+     * @param source A character source implementing the Readable interface
+     * @param pattern A delimiting pattern
+     */
+    private Scanner(Readable source, Pattern pattern) {
+        assert source != null : "source should not be null";
+        assert pattern != null : "pattern should not be null";
+        this.source = source;
+        delimPattern = pattern;
+        buf = CharBuffer.allocate(BUFFER_SIZE);
+        buf.limit(0);
+        matcher = delimPattern.matcher(buf);
+        matcher.useTransparentBounds(true);
+        matcher.useAnchoringBounds(false);
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified source.
+     *
+     * @param  source A character source implementing the {@link Readable}
+     *         interface
+     */
+    public Scanner(Readable source) {
+        this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source An input stream to be scanned
+     */
+    public Scanner(InputStream source) {
+        this(new InputStreamReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the specified charset.
+     *
+     * @param  source An input stream to be scanned
+     * @param charsetName The encoding type used to convert bytes from the
+     *        stream into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(InputStream source, String charsetName) {
+        this(source, toCharset(charsetName));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the specified charset.
+     *
+     * @param  source an input stream to be scanned
+     * @param  charset the charset used to convert bytes from the file
+     *         into characters to be scanned
+     * @since  10
+     */
+    public Scanner(InputStream source, Charset charset) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), charset),
+             WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws IllegalArgumentException      if the charset is not supported
+     */
+    private static Charset toCharset(String csn) {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
+            // IllegalArgumentException should be thrown
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /*
+     * This method is added so that null-check on charset can be performed before
+     * creating InputStream as an existing test required it.
+     */
+    private static Readable makeReadable(Path source, Charset charset)
+            throws IOException {
+        Objects.requireNonNull(charset, "charset");
+        return makeReadable(Files.newInputStream(source), charset);
+    }
+
+    private static Readable makeReadable(InputStream source, Charset charset) {
+        Objects.requireNonNull(charset, "charset");
+        return new InputStreamReader(source, charset);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A file to be scanned
+     * @throws FileNotFoundException if source is not found
+     */
+    public Scanner(File source) throws FileNotFoundException {
+        this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A file to be scanned
+     * @param charsetName The encoding type used to convert bytes from the file
+     *        into characters to be scanned
+     * @throws FileNotFoundException if source is not found
+     * @throws IllegalArgumentException if the specified encoding is
+     *         not found
+     */
+    public Scanner(File source, String charsetName)
+        throws FileNotFoundException
+    {
+        this(Objects.requireNonNull(source), toDecoder(charsetName));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A file to be scanned
+     * @param  charset The charset used to convert bytes from the file
+     *         into characters to be scanned
+     * @throws IOException
+     *         if an I/O error occurs opening the source
+     * @since  10
+     */
+    public Scanner(File source, Charset charset) throws IOException {
+        this(Objects.requireNonNull(source), charset.newDecoder());
+    }
+
+    private Scanner(File source, CharsetDecoder dec)
+        throws FileNotFoundException
+    {
+        this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
+    }
+
+    private static CharsetDecoder toDecoder(String charsetName) {
+        // Android-changed: Throw an IAE instead of an NPE.
+        // Objects.requireNonNull(charsetName, "charsetName");
+        if (charsetName == null) {
+            throw new IllegalArgumentException("charsetName == null");
+        }
+        try {
+            return Charset.forName(charsetName).newDecoder();
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            throw new IllegalArgumentException(charsetName);
+        }
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source,
+                                         CharsetDecoder dec) {
+        return Channels.newReader(source, dec, -1);
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source,
+                                         Charset charset) {
+        Objects.requireNonNull(charset, "charset");
+        return Channels.newReader(source, charset);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     *
+     * @since   1.7
+     */
+    public Scanner(Path source)
+        throws IOException
+    {
+        this(Files.newInputStream(source));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @param   charsetName
+     *          The encoding type used to convert bytes from the file
+     *          into characters to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     * @throws  IllegalArgumentException
+     *          if the specified encoding is not found
+     * @since   1.7
+     */
+    public Scanner(Path source, String charsetName) throws IOException {
+        this(Objects.requireNonNull(source), toCharset(charsetName));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @param   charset
+     *          the charset used to convert bytes from the file
+     *          into characters to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening the source
+     * @since   10
+     */
+    public Scanner(Path source, Charset charset)  throws IOException {
+        this(makeReadable(source, charset));
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified string.
+     *
+     * @param  source A string to scan
+     */
+    public Scanner(String source) {
+        this(new StringReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A channel to scan
+     */
+    public Scanner(ReadableByteChannel source) {
+        this(makeReadable(Objects.requireNonNull(source, "source")),
+             WHITESPACE_PATTERN);
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source) {
+        return makeReadable(source, Charset.defaultCharset().newDecoder());
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A channel to scan
+     * @param charsetName The encoding type used to convert bytes from the
+     *        channel into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(ReadableByteChannel source, String charsetName) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), toDecoder(charsetName)),
+             WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new {@code Scanner} that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the specified charset.
+     *
+     * @param source a channel to scan
+     * @param charset the encoding type used to convert bytes from the
+     *        channel into characters to be scanned
+     * @since 10
+     */
+    public Scanner(ReadableByteChannel source, Charset charset) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), charset),
+             WHITESPACE_PATTERN);
+    }
+
+    // Private primitives used to support scanning
+
+    private void saveState() {
+        savedScannerPosition = position;
+    }
+
+    private void revertState() {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+    }
+
+    private boolean revertState(boolean b) {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+        return b;
+    }
+
+    private void cacheResult() {
+        hasNextResult = matcher.group();
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    private void cacheResult(String result) {
+        hasNextResult = result;
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    // Clears both regular cache and type cache
+    private void clearCaches() {
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private String getCachedResult() {
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+        return hasNextResult;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private void useTypeCache() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Tries to read more input. May block.
+    private void readInput() {
+        if (buf.limit() == buf.capacity())
+            makeSpace();
+        // Prepare to receive data
+        int p = buf.position();
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+
+        int n = 0;
+        try {
+            n = source.read(buf);
+        } catch (IOException ioe) {
+            lastException = ioe;
+            n = -1;
+        }
+        if (n == -1) {
+            sourceClosed = true;
+            needInput = false;
+        }
+        if (n > 0)
+            needInput = false;
+        // Restore current position and limit for reading
+        buf.limit(buf.position());
+        buf.position(p);
+        // Android-added: reset() the matcher after reading.
+        // The matcher implementation eagerly calls toString() so we'll have
+        // to update its input whenever the buffer limit, position etc. changes.
+        matcher.reset(buf);
+    }
+
+    // After this method is called there will either be an exception
+    // or else there will be space in the buffer
+    private boolean makeSpace() {
+        clearCaches();
+        int offset = savedScannerPosition == -1 ?
+            position : savedScannerPosition;
+        buf.position(offset);
+        // Gain space by compacting buffer
+        if (offset > 0) {
+            buf.compact();
+            translateSavedIndexes(offset);
+            position -= offset;
+            buf.flip();
+            return true;
+        }
+        // Gain space by growing buffer
+        int newSize = buf.capacity() * 2;
+        CharBuffer newBuf = CharBuffer.allocate(newSize);
+        newBuf.put(buf);
+        newBuf.flip();
+        translateSavedIndexes(offset);
+        position -= offset;
+        buf = newBuf;
+        matcher.reset(buf);
+        return true;
+    }
+
+    // When a buffer compaction/reallocation occurs the saved indexes must
+    // be modified appropriately
+    private void translateSavedIndexes(int offset) {
+        if (savedScannerPosition != -1)
+            savedScannerPosition -= offset;
+    }
+
+    // If we are at the end of input then NoSuchElement;
+    // If there is still input left then InputMismatch
+    private void throwFor() {
+        skipped = false;
+        if ((sourceClosed) && (position == buf.limit()))
+            throw new NoSuchElementException();
+        else
+            throw new InputMismatchException();
+    }
+
+    // Returns true if a complete token or partial token is in the buffer.
+    // It is not necessary to find a complete token since a partial token
+    // means that there will be another token with or without more input.
+    private boolean hasTokenInBuffer() {
+        matchValid = false;
+        matcher.usePattern(delimPattern);
+        matcher.region(position, buf.limit());
+        // Skip delims first
+        if (matcher.lookingAt()) {
+            if (matcher.hitEnd() && !sourceClosed) {
+                // more input might change the match of delims, in which
+                // might change whether or not if there is token left in
+                // buffer (don't update the "position" in this case)
+                needInput = true;
+                return false;
+            }
+            position = matcher.end();
+        }
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit())
+            return false;
+        return true;
+    }
+
+    /*
+     * Returns a "complete token" that matches the specified pattern
+     *
+     * A token is complete if surrounded by delims; a partial token
+     * is prefixed by delims but not postfixed by them
+     *
+     * The position is advanced to the end of that complete token
+     *
+     * Pattern == null means accept any token at all
+     *
+     * Triple return:
+     * 1. valid string means it was found
+     * 2. null with needInput=false means we won't ever find it
+     * 3. null with needInput=true means try again after readInput
+     */
+    private String getCompleteTokenInBuffer(Pattern pattern) {
+        matchValid = false;
+        // Skip delims first
+        matcher.usePattern(delimPattern);
+        if (!skipped) { // Enforcing only one skip of leading delims
+            matcher.region(position, buf.limit());
+            if (matcher.lookingAt()) {
+                // If more input could extend the delimiters then we must wait
+                // for more input
+                if (matcher.hitEnd() && !sourceClosed) {
+                    needInput = true;
+                    return null;
+                }
+                // The delims were whole and the matcher should skip them
+                skipped = true;
+                position = matcher.end();
+            }
+        }
+
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit()) {
+            if (sourceClosed)
+                return null;
+            needInput = true;
+            return null;
+        }
+        // Must look for next delims. Simply attempting to match the
+        // pattern at this point may find a match but it might not be
+        // the first longest match because of missing input, or it might
+        // match a partial token instead of the whole thing.
+
+        // Then look for next delims
+        matcher.region(position, buf.limit());
+        boolean foundNextDelim = matcher.find();
+        if (foundNextDelim && (matcher.end() == position)) {
+            // Zero length delimiter match; we should find the next one
+            // using the automatic advance past a zero length match;
+            // Otherwise we have just found the same one we just skipped
+            foundNextDelim = matcher.find();
+        }
+        if (foundNextDelim) {
+            // In the rare case that more input could cause the match
+            // to be lost and there is more input coming we must wait
+            // for more input. Note that hitting the end is okay as long
+            // as the match cannot go away. It is the beginning of the
+            // next delims we want to be sure about, we don't care if
+            // they potentially extend further.
+            if (matcher.requireEnd() && !sourceClosed) {
+                needInput = true;
+                return null;
+            }
+            int tokenEnd = matcher.start();
+            // There is a complete token.
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            //  Attempt to match against the desired pattern
+            matcher.usePattern(pattern);
+            matcher.region(position, tokenEnd);
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            } else { // Complete token but it does not match
+                return null;
+            }
+        }
+
+        // If we can't find the next delims but no more input is coming,
+        // then we can treat the remainder as a whole token
+        if (sourceClosed) {
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            // Last token; Match the pattern here or throw
+            matcher.usePattern(pattern);
+            matcher.region(position, buf.limit());
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            }
+            // Last piece does not match
+            return null;
+        }
+
+        // There is a partial token in the buffer; must read more
+        // to complete it
+        needInput = true;
+        return null;
+    }
+
+    // Finds the specified pattern in the buffer up to horizon.
+    // Returns true if the specified input pattern was matched,
+    // and leaves the matcher field with the current match state.
+    private boolean findPatternInBuffer(Pattern pattern, int horizon) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        int bufferLimit = buf.limit();
+        int horizonLimit = -1;
+        int searchLimit = bufferLimit;
+        if (horizon > 0) {
+            horizonLimit = position + horizon;
+            if (horizonLimit < bufferLimit)
+                searchLimit = horizonLimit;
+        }
+        matcher.region(position, searchLimit);
+        if (matcher.find()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // The match may be longer if didn't hit horizon or real end
+                if (searchLimit != horizonLimit) {
+                     // Hit an artificial end; try to extend the match
+                    needInput = true;
+                    return false;
+                }
+                // The match could go away depending on what is next
+                if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
+                    // Rare case: we hit the end of input and it happens
+                    // that it is at the horizon and the end of input is
+                    // required for the match.
+                    needInput = true;
+                    return false;
+                }
+            }
+            // Did not hit end, or hit real end, or hit horizon
+            position = matcher.end();
+            return true;
+        }
+
+        if (sourceClosed)
+            return false;
+
+        // If there is no specified horizon, or if we have not searched
+        // to the specified horizon yet, get more input
+        if ((horizon == 0) || (searchLimit != horizonLimit))
+            needInput = true;
+        return false;
+    }
+
+    // Attempts to match a pattern anchored at the current position.
+    // Returns true if the specified input pattern was matched,
+    // and leaves the matcher field with the current match state.
+    private boolean matchPatternInBuffer(Pattern pattern) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        matcher.region(position, buf.limit());
+        if (matcher.lookingAt()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // Get more input and try again
+                needInput = true;
+                return false;
+            }
+            position = matcher.end();
+            return true;
+        }
+
+        if (sourceClosed)
+            return false;
+
+        // Read more to find pattern
+        needInput = true;
+        return false;
+    }
+
+    // Throws if the scanner is closed
+    private void ensureOpen() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+    }
+
+    // Public methods
+
+    /**
+     * Closes this scanner.
+     *
+     * <p> If this scanner has not yet been closed then if its underlying
+     * {@linkplain java.lang.Readable readable} also implements the {@link
+     * java.io.Closeable} interface then the readable's {@code close} method
+     * will be invoked.  If this scanner is already closed then invoking this
+     * method will have no effect.
+     *
+     * <p>Attempting to perform search operations after a scanner has
+     * been closed will result in an {@link IllegalStateException}.
+     *
+     */
+    public void close() {
+        if (closed)
+            return;
+        if (source instanceof Closeable) {
+            try {
+                ((Closeable)source).close();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+        sourceClosed = true;
+        source = null;
+        closed = true;
+    }
+
+    /**
+     * Returns the {@code IOException} last thrown by this
+     * {@code Scanner}'s underlying {@code Readable}. This method
+     * returns {@code null} if no such exception exists.
+     *
+     * @return the last exception thrown by this scanner's readable
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Returns the {@code Pattern} this {@code Scanner} is currently
+     * using to match delimiters.
+     *
+     * @return this scanner's delimiting pattern.
+     */
+    public Pattern delimiter() {
+        return delimPattern;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to the specified pattern.
+     *
+     * @param pattern A delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(Pattern pattern) {
+        modCount++;
+        delimPattern = pattern;
+        return this;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to a pattern constructed from
+     * the specified {@code String}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code useDelimiter(pattern)} behaves in exactly the same way as the
+     * invocation {@code useDelimiter(Pattern.compile(pattern))}.
+     *
+     * <p> Invoking the {@link #reset} method will set the scanner's delimiter
+     * to the <a href= "#default-delimiter">default</a>.
+     *
+     * @param pattern A string specifying a delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(String pattern) {
+        modCount++;
+        delimPattern = patternCache.forName(pattern);
+        return this;
+    }
+
+    /**
+     * Returns this scanner's locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return this scanner's locale
+     */
+    public Locale locale() {
+        return this.locale;
+    }
+
+    /**
+     * Sets this scanner's locale to the specified locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's locale to
+     * the <a href= "#initial-locale">initial locale</a>.
+     *
+     * @param locale A string specifying the locale to use
+     * @return this scanner
+     */
+    public Scanner useLocale(Locale locale) {
+        if (locale.equals(this.locale))
+            return this;
+
+        modCount++;
+        this.locale = locale;
+
+        DecimalFormat df = null;
+        NumberFormat nf = NumberFormat.getNumberInstance(locale);
+        DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
+
+        // Android-changed: nf is DecimalFormat.
+        /*
+        if (nf instanceof DecimalFormat) {
+             df = (DecimalFormat) nf;
+        } else {
+
+            // In case where NumberFormat.getNumberInstance() returns
+            // other instance (non DecimalFormat) based on the provider
+            // used and java.text.spi.NumberFormatProvider implementations,
+            // DecimalFormat constructor is used to obtain the instance
+            LocaleProviderAdapter adapter = LocaleProviderAdapter
+                    .getAdapter(NumberFormatProvider.class, locale);
+            if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+                adapter = LocaleProviderAdapter.getResourceBundleBased();
+            }
+            String[] all = adapter.getLocaleResources(locale)
+                    .getNumberPatterns();
+            df = new DecimalFormat(all[0], dfs);
+        }
+        */
+        df = (DecimalFormat) nf;
+
+        // These must be literalized to avoid collision with regex
+        // metacharacters such as dot or parenthesis
+        groupSeparator =   "\\x{" + Integer.toHexString(dfs.getGroupingSeparator()) + "}";
+        decimalSeparator = "\\x{" + Integer.toHexString(dfs.getDecimalSeparator()) + "}";
+
+        // Quoting the nonzero length locale-specific things
+        // to avoid potential conflict with metacharacters
+        nanString = Pattern.quote(dfs.getNaN());
+        infinityString = Pattern.quote(dfs.getInfinity());
+        positivePrefix = df.getPositivePrefix();
+        if (!positivePrefix.isEmpty())
+            positivePrefix = Pattern.quote(positivePrefix);
+        negativePrefix = df.getNegativePrefix();
+        if (!negativePrefix.isEmpty())
+            negativePrefix = Pattern.quote(negativePrefix);
+        positiveSuffix = df.getPositiveSuffix();
+        if (!positiveSuffix.isEmpty())
+            positiveSuffix = Pattern.quote(positiveSuffix);
+        negativeSuffix = df.getNegativeSuffix();
+        if (!negativeSuffix.isEmpty())
+            negativeSuffix = Pattern.quote(negativeSuffix);
+
+        // Force rebuilding and recompilation of locale dependent
+        // primitive patterns
+        integerPattern = null;
+        floatPattern = null;
+
+        return this;
+    }
+
+    /**
+     * Returns this scanner's default radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return the default radix of this scanner
+     */
+    public int radix() {
+        return this.defaultRadix;
+    }
+
+    /**
+     * Sets this scanner's default radix to the specified radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's radix to
+     * {@code 10}.
+     *
+     * @param radix The radix to use when scanning numbers
+     * @return this scanner
+     * @throws IllegalArgumentException if radix is out of range
+     */
+    public Scanner useRadix(int radix) {
+        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
+            throw new IllegalArgumentException("radix:"+radix);
+
+        if (this.defaultRadix == radix)
+            return this;
+        modCount++;
+        this.defaultRadix = radix;
+        // Force rebuilding and recompilation of radix dependent patterns
+        integerPattern = null;
+        return this;
+    }
+
+    // The next operation should occur in the specified radix but
+    // the default is left untouched.
+    private void setRadix(int radix) {
+        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
+            throw new IllegalArgumentException("radix:"+radix);
+
+        if (this.radix != radix) {
+            // Force rebuilding and recompilation of radix dependent patterns
+            integerPattern = null;
+            this.radix = radix;
+        }
+    }
+
+    /**
+     * Returns the match result of the last scanning operation performed
+     * by this scanner. This method throws {@code IllegalStateException}
+     * if no match has been performed, or if the last match was
+     * not successful.
+     *
+     * <p>The various {@code next} methods of {@code Scanner}
+     * make a match result available if they complete without throwing an
+     * exception. For instance, after an invocation of the {@link #nextInt}
+     * method that returned an int, this method returns a
+     * {@code MatchResult} for the search of the
+     * <a href="#Integer-regex"><i>Integer</i></a> regular expression
+     * defined above. Similarly the {@link #findInLine findInLine()},
+     * {@link #findWithinHorizon findWithinHorizon()}, and {@link #skip skip()}
+     * methods will make a match available if they succeed.
+     *
+     * @return a match result for the last match operation
+     * @throws IllegalStateException  If no match result is available
+     */
+    public MatchResult match() {
+        if (!matchValid)
+            throw new IllegalStateException("No match result available");
+        return matcher.toMatchResult();
+    }
+
+    /**
+     * <p>Returns the string representation of this {@code Scanner}. The
+     * string representation of a {@code Scanner} contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this scanner
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.Scanner");
+        sb.append("[delimiters=" + delimPattern + "]");
+        sb.append("[position=" + position + "]");
+        sb.append("[match valid=" + matchValid + "]");
+        sb.append("[need input=" + needInput + "]");
+        sb.append("[source closed=" + sourceClosed + "]");
+        sb.append("[skipped=" + skipped + "]");
+        sb.append("[group separator=" + groupSeparator + "]");
+        sb.append("[decimal separator=" + decimalSeparator + "]");
+        sb.append("[positive prefix=" + positivePrefix + "]");
+        sb.append("[negative prefix=" + negativePrefix + "]");
+        sb.append("[positive suffix=" + positiveSuffix + "]");
+        sb.append("[negative suffix=" + negativeSuffix + "]");
+        sb.append("[NaN string=" + nanString + "]");
+        sb.append("[infinity string=" + infinityString + "]");
+        return sb.toString();
+    }
+
+    /**
+     * Returns true if this scanner has another token in its input.
+     * This method may block while waiting for input to scan.
+     * The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner has another token
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public boolean hasNext() {
+        ensureOpen();
+        saveState();
+        modCount++;
+        while (!sourceClosed) {
+            if (hasTokenInBuffer()) {
+                return revertState(true);
+            }
+            readInput();
+        }
+        boolean result = hasTokenInBuffer();
+        return revertState(result);
+    }
+
+    /**
+     * Finds and returns the next complete token from this scanner.
+     * A complete token is preceded and followed by input that matches
+     * the delimiter pattern. This method may block while waiting for input
+     * to scan, even if a previous invocation of {@link #hasNext} returned
+     * {@code true}.
+     *
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public String next() {
+        ensureOpen();
+        clearCaches();
+        modCount++;
+        while (true) {
+            String token = getCompleteTokenInBuffer(null);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * The remove operation is not supported by this implementation of
+     * {@code Iterator}.
+     *
+     * @throws UnsupportedOperationException if this method is invoked.
+     * @see java.util.Iterator
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns true if the next token matches the pattern constructed from the
+     * specified string. The scanner does not advance past any input.
+     *
+     * <p> An invocation of this method of the form {@code hasNext(pattern)}
+     * behaves in exactly the same way as the invocation
+     * {@code hasNext(Pattern.compile(pattern))}.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(String pattern)  {
+        return hasNext(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns the next token if it matches the pattern constructed from the
+     * specified string.  If the match is successful, the scanner advances
+     * past the input that matched the pattern.
+     *
+     * <p> An invocation of this method of the form {@code next(pattern)}
+     * behaves in exactly the same way as the invocation
+     * {@code next(Pattern.compile(pattern))}.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return the next token
+     * @throws NoSuchElementException if no such tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(String pattern)  {
+        return next(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns true if the next complete token matches the specified pattern.
+     * A complete token is prefixed and postfixed by input that matches
+     * the delimiter pattern. This method may block while waiting for input.
+     * The scanner does not advance past any input.
+     *
+     * @param pattern the pattern to scan for
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        hasNextPattern = null;
+        saveState();
+        modCount++;
+
+        while (true) {
+            if (getCompleteTokenInBuffer(pattern) != null) {
+                matchValid = true;
+                cacheResult();
+                return revertState(true);
+            }
+            if (needInput)
+                readInput();
+            else
+                return revertState(false);
+        }
+    }
+
+    /**
+     * Returns the next token if it matches the specified pattern. This
+     * method may block while waiting for input to scan, even if a previous
+     * invocation of {@link #hasNext(Pattern)} returned {@code true}.
+     * If the match is successful, the scanner advances past the input that
+     * matched the pattern.
+     *
+     * @param pattern the pattern to scan for
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+
+        modCount++;
+        // Did we already find this pattern?
+        if (hasNextPattern == pattern)
+            return getCachedResult();
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = getCompleteTokenInBuffer(pattern);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * Returns true if there is another line in the input of this scanner.
+     * This method may block while waiting for input. The scanner does not
+     * advance past any input.
+     *
+     * @return true if and only if this scanner has another line of input
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLine() {
+        saveState();
+
+        modCount++;
+        String result = findWithinHorizon(linePattern(), 0);
+        if (result != null) {
+            MatchResult mr = this.match();
+            String lineSep = mr.group(1);
+            if (lineSep != null) {
+                result = result.substring(0, result.length() -
+                                          lineSep.length());
+                cacheResult(result);
+
+            } else {
+                cacheResult();
+            }
+        }
+        revertState();
+        return (result != null);
+    }
+
+    /**
+     * Advances this scanner past the current line and returns the input
+     * that was skipped.
+     *
+     * This method returns the rest of the current line, excluding any line
+     * separator at the end. The position is set to the beginning of the next
+     * line.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for a line separator, it may buffer all of the input searching for
+     * the line to skip if no line separators are present.
+     *
+     * @return the line that was skipped
+     * @throws NoSuchElementException if no line was found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String nextLine() {
+        modCount++;
+        if (hasNextPattern == linePattern())
+            return getCachedResult();
+        clearCaches();
+
+        String result = findWithinHorizon(linePattern, 0);
+        if (result == null)
+            throw new NoSuchElementException("No line found");
+        MatchResult mr = this.match();
+        String lineSep = mr.group(1);
+        if (lineSep != null)
+            result = result.substring(0, result.length() - lineSep.length());
+        if (result == null)
+            throw new NoSuchElementException();
+        else
+            return result;
+    }
+
+    // Public methods that ignore delimiters
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form {@code findInLine(pattern)}
+     * behaves in exactly the same way as the invocation
+     * {@code findInLine(Pattern.compile(pattern))}.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(String pattern) {
+        return findInLine(patternCache.forName(pattern));
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern ignoring
+     * delimiters. If the pattern is found before the next line separator, the
+     * scanner advances past the input that matched and returns the string that
+     * matched the pattern.
+     * If no such pattern is detected in the input up to the next line
+     * separator, then {@code null} is returned and the scanner's
+     * position is unchanged. This method may block waiting for input that
+     * matches the pattern.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for the specified pattern, it may buffer all of the input searching for
+     * the desired token if no line separators are present.
+     *
+     * @param pattern the pattern to scan for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+        modCount++;
+        // Expand buffer to include the next newline or end of input
+        int endPosition = 0;
+        saveState();
+        while (true) {
+            if (findPatternInBuffer(separatorPattern(), 0)) {
+                endPosition = matcher.start();
+                break; // up to next newline
+            }
+            if (needInput) {
+                readInput();
+            } else {
+                endPosition = buf.limit();
+                break; // up to end of input
+            }
+        }
+        revertState();
+        int horizonForLine = endPosition - position;
+        // If there is nothing between the current pos and the next
+        // newline simply return null, invoking findWithinHorizon
+        // with "horizon=0" will scan beyond the line bound.
+        if (horizonForLine == 0)
+            return null;
+        // Search for the pattern
+        return findWithinHorizon(pattern, horizonForLine);
+    }
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form
+     * {@code findWithinHorizon(pattern)} behaves in exactly the same way as
+     * the invocation
+     * {@code findWithinHorizon(Pattern.compile(pattern), horizon)}.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(String pattern, int horizon) {
+        return findWithinHorizon(patternCache.forName(pattern), horizon);
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern.
+     *
+     * <p>This method searches through the input up to the specified
+     * search horizon, ignoring delimiters. If the pattern is found the
+     * scanner advances past the input that matched and returns the string
+     * that matched the pattern. If no such pattern is detected then the
+     * null is returned and the scanner's position remains unchanged. This
+     * method may block waiting for input that matches the pattern.
+     *
+     * <p>A scanner will never search more than {@code horizon} code
+     * points beyond its current position. Note that a match may be clipped
+     * by the horizon; that is, an arbitrary match result may have been
+     * different if the horizon had been larger. The scanner treats the
+     * horizon as a transparent, non-anchoring bound (see {@link
+     * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}).
+     *
+     * <p>If horizon is {@code 0}, then the horizon is ignored and
+     * this method continues to search through the input looking for the
+     * specified pattern without bound. In this case it may buffer all of
+     * the input searching for the pattern.
+     *
+     * <p>If horizon is negative, then an IllegalArgumentException is
+     * thrown.
+     *
+     * @param pattern the pattern to scan for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(Pattern pattern, int horizon) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        if (horizon < 0)
+            throw new IllegalArgumentException("horizon < 0");
+        clearCaches();
+        modCount++;
+
+        // Search for the pattern
+        while (true) {
+            if (findPatternInBuffer(pattern, horizon)) {
+                matchValid = true;
+                return matcher.group();
+            }
+            if (needInput)
+                readInput();
+            else
+                break; // up to end of input
+        }
+        return null;
+    }
+
+    /**
+     * Skips input that matches the specified pattern, ignoring delimiters.
+     * This method will skip input if an anchored match of the specified
+     * pattern succeeds.
+     *
+     * <p>If a match to the specified pattern is not found at the
+     * current position, then no input is skipped and a
+     * {@code NoSuchElementException} is thrown.
+     *
+     * <p>Since this method seeks to match the specified pattern starting at
+     * the scanner's current position, patterns that can match a lot of
+     * input (".*", for example) may cause the scanner to buffer a large
+     * amount of input.
+     *
+     * <p>Note that it is possible to skip something without risking a
+     * {@code NoSuchElementException} by using a pattern that can
+     * match nothing, e.g., {@code sc.skip("[ \t]*")}.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws NoSuchElementException if the specified pattern is not found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+        modCount++;
+
+        // Search for the pattern
+        while (true) {
+            if (matchPatternInBuffer(pattern)) {
+                matchValid = true;
+                position = matcher.end();
+                return this;
+            }
+            if (needInput)
+                readInput();
+            else
+                throw new NoSuchElementException();
+        }
+    }
+
+    /**
+     * Skips input that matches a pattern constructed from the specified
+     * string.
+     *
+     * <p> An invocation of this method of the form {@code skip(pattern)}
+     * behaves in exactly the same way as the invocation
+     * {@code skip(Pattern.compile(pattern))}.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(String pattern) {
+        return skip(patternCache.forName(pattern));
+    }
+
+    // Convenience methods for scanning primitives
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a boolean value using a case insensitive pattern
+     * created from the string "true|false".  The scanner does not
+     * advance past the input that matched.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         boolean value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBoolean()  {
+        return hasNext(boolPattern());
+    }
+
+    /**
+     * Scans the next token of the input into a boolean value and returns
+     * that value. This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid boolean value.
+     * If the match is successful, the scanner advances past the input that
+     * matched.
+     *
+     * @return the boolean scanned from the input
+     * @throws InputMismatchException if the next token is not a valid boolean
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean nextBoolean()  {
+        clearCaches();
+        return Boolean.parseBoolean(next(boolPattern()));
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the default radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextByte() {
+        return hasNextByte(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the specified radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public boolean hasNextByte(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Byte.parseByte(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@code byte}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code nextByte()} behaves in exactly the same way as the
+     * invocation {@code nextByte(radix)}, where {@code radix}
+     * is the default radix of this scanner.
+     *
+     * @return the {@code byte} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public byte nextByte() {
+         return nextByte(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@code byte}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid byte value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a {@code byte} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Byte#parseByte(String, int) Byte.parseByte} with the
+     * specified radix.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return the {@code byte} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public byte nextByte(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Byte)
+            && this.radix == radix) {
+            byte val = ((Byte)typeCache).byteValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next byte
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Byte.parseByte(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the default radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the default radix
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextShort() {
+        return hasNextShort(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the specified radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the specified radix
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public boolean hasNextShort(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Short.parseShort(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@code short}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code nextShort()} behaves in exactly the same way as the
+     * invocation {@link #nextShort(int) nextShort(radix)}, where {@code radix}
+     * is the default radix of this scanner.
+     *
+     * @return the {@code short} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public short nextShort() {
+        return nextShort(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@code short}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid short value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a {@code short} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Short#parseShort(String, int) Short.parseShort} with the
+     * specified radix.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return the {@code short} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public short nextShort(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Short)
+            && this.radix == radix) {
+            short val = ((Short)typeCache).shortValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next short
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Short.parseShort(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the default radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextInt() {
+        return hasNextInt(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the specified radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public boolean hasNextInt(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Integer.parseInt(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * The integer token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parse will accept it.
+     */
+    private String processIntegerToken(String token) {
+        String result = token.replaceAll(""+groupSeparator, "");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (isNegative)
+            result = "-" + result;
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as an {@code int}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code nextInt()} behaves in exactly the same way as the
+     * invocation {@code nextInt(radix)}, where {@code radix}
+     * is the default radix of this scanner.
+     *
+     * @return the {@code int} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public int nextInt() {
+        return nextInt(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as an {@code int}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid int value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into an {@code int} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Integer#parseInt(String, int) Integer.parseInt} with the
+     * specified radix.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the {@code int} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public int nextInt(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Integer)
+            && this.radix == radix) {
+            int val = ((Integer)typeCache).intValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Integer.parseInt(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the default radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLong() {
+        return hasNextLong(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the specified radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as a long value
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public boolean hasNextLong(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Long.parseLong(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@code long}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code nextLong()} behaves in exactly the same way as the
+     * invocation {@code nextLong(radix)}, where {@code radix}
+     * is the default radix of this scanner.
+     *
+     * @return the {@code long} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public long nextLong() {
+        return nextLong(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@code long}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid long value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a {@code long} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Long#parseLong(String, int) Long.parseLong} with the
+     * specified radix.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the {@code long} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public long nextLong(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Long)
+            && this.radix == radix) {
+            long val = ((Long)typeCache).longValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Long.parseLong(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * The float token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parseFloat will accept it.
+     *
+     * If there are non-ascii digits in the token these digits must
+     * be processed before the token is passed to parseFloat.
+     */
+    private String processFloatToken(String token) {
+        String result = token.replaceAll(groupSeparator, "");
+        if (!decimalSeparator.equals("\\."))
+            result = result.replaceAll(decimalSeparator, ".");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (result.equals(nanString))
+            result = "NaN";
+        if (result.equals(infinityString))
+            result = "Infinity";
+        // BEGIN Android-added: Match the infinity symbol.
+        if (result.equals("\u221E"))
+            result = "Infinity";
+        // END Android-added: Match the infinity symbol.
+        if (isNegative)
+            result = "-" + result;
+
+        // Translate non-ASCII digits
+        Matcher m = NON_ASCII_DIGIT.matcher(result);
+        if (m.find()) {
+            StringBuilder inASCII = new StringBuilder();
+            for (int i=0; i<result.length(); i++) {
+                char nextChar = result.charAt(i);
+                if (Character.isDigit(nextChar)) {
+                    int d = Character.digit(nextChar, 10);
+                    if (d != -1)
+                        inASCII.append(d);
+                    else
+                        inASCII.append(nextChar);
+                } else {
+                    inASCII.append(nextChar);
+                }
+            }
+            result = inASCII.toString();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a float value using the {@link #nextFloat}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         float value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextFloat() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Float.valueOf(Float.parseFloat(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@code float}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid float value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a {@code float} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Float#parseFloat Float.parseFloat}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Float#parseFloat(String) Float.parseFloat} as
+     * appropriate.
+     *
+     * @return the {@code float} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public float nextFloat() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Float)) {
+            float val = ((Float)typeCache).floatValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        try {
+            return Float.parseFloat(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a double value using the {@link #nextDouble}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         double value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextDouble() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Double.valueOf(Double.parseDouble(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@code double}.
+     * This method will throw {@code InputMismatchException}
+     * if the next token cannot be translated into a valid double value.
+     * If the translation is successful, the scanner advances past the input
+     * that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a {@code double} value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Double#parseDouble Double.parseDouble}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Double#parseDouble(String) Double.parseDouble} as
+     * appropriate.
+     *
+     * @return the {@code double} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public double nextDouble() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Double)) {
+            double val = ((Double)typeCache).doubleValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            return Double.parseDouble(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    // Convenience methods for scanning multi precision numbers
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a {@code BigInteger} in the default radix using the
+     * {@link #nextBigInteger} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         {@code BigInteger}
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigInteger() {
+        return hasNextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a {@code BigInteger} in the specified radix using
+     * the {@link #nextBigInteger} method. The scanner does not advance past
+     * any input.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token as an integer
+     * @return true if and only if this scanner's next token is a valid
+     *         {@code BigInteger}
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public boolean hasNextBigInteger(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = new BigInteger(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code nextBigInteger()} behaves in exactly the same way as the
+     * invocation {@code nextBigInteger(radix)}, where {@code radix}
+     * is the default radix of this scanner.
+     *
+     * @return the {@code BigInteger} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigInteger nextBigInteger() {
+        return nextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a {@code BigInteger} value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigInteger#BigInteger(java.lang.String)
+     * BigInteger(String, int)} constructor with the specified radix.
+     *
+     * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
+     * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
+     * {@code IllegalArgumentException} is thrown.
+     *
+     * @param radix the radix used to interpret the token
+     * @return the {@code BigInteger} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if the radix is out of range
+     */
+    public BigInteger nextBigInteger(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigInteger val)
+            && this.radix == radix) {
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return new BigInteger(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a {@code BigDecimal} using the
+     * {@link #nextBigDecimal} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         {@code BigDecimal}
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigDecimal() {
+        setRadix(10);
+        boolean result = hasNext(decimalPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = new BigDecimal(s);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigDecimal
+     * BigDecimal}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Decimal-regex"><i>Decimal</i></a> regular expression defined
+     * above then the token is converted into a {@code BigDecimal} value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigDecimal#BigDecimal(java.lang.String) BigDecimal(String)}
+     * constructor.
+     *
+     * @return the {@code BigDecimal} scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Decimal</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigDecimal nextBigDecimal() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigDecimal val)) {
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            String s = processFloatToken(next(decimalPattern()));
+            return new BigDecimal(s);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Resets this scanner.
+     *
+     * <p> Resetting a scanner discards all of its explicit state
+     * information which may have been changed by invocations of
+     * {@link #useDelimiter useDelimiter()},
+     * {@link #useLocale useLocale()}, or
+     * {@link #useRadix useRadix()}.
+     *
+     * <p> An invocation of this method of the form
+     * {@code scanner.reset()} behaves in exactly the same way as the
+     * invocation
+     *
+     * <blockquote><pre>{@code
+     *   scanner.useDelimiter("\\p{javaWhitespace}+")
+     *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
+     *          .useRadix(10);
+     * }</pre></blockquote>
+     *
+     * @return this scanner
+     *
+     * @since 1.6
+     */
+    public Scanner reset() {
+        delimPattern = WHITESPACE_PATTERN;
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+        useRadix(10);
+        clearCaches();
+        modCount++;
+        return this;
+    }
+
+    /**
+     * Returns a stream of delimiter-separated tokens from this scanner. The
+     * stream contains the same tokens that would be returned, starting from
+     * this scanner's current state, by calling the {@link #next} method
+     * repeatedly until the {@link #hasNext} method returns false.
+     *
+     * <p>The resulting stream is sequential and ordered. All stream elements are
+     * non-null.
+     *
+     * <p>Scanning starts upon initiation of the terminal stream operation, using the
+     * current state of this scanner. Subsequent calls to any methods on this scanner
+     * other than {@link #close} and {@link #ioException} may return undefined results
+     * or may cause undefined effects on the returned stream. The returned stream's source
+     * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if any such calls are detected
+     * during stream pipeline execution.
+     *
+     * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
+     * state and cannot be reused.
+     *
+     * <p>If this scanner contains a resource that must be released, this scanner
+     * should be closed, either by calling its {@link #close} method, or by
+     * closing the returned stream. Closing the stream will close the underlying scanner.
+     * {@code IllegalStateException} is thrown if the scanner has been closed when this
+     * method is called, or if this scanner is closed during stream pipeline execution.
+     *
+     * <p>This method might block waiting for more input.
+     *
+     * @apiNote
+     * For example, the following code will create a list of
+     * comma-delimited tokens from a string:
+     *
+     * <pre>{@code
+     * List<String> result = new Scanner("abc,def,,ghi")
+     *     .useDelimiter(",")
+     *     .tokens()
+     *     .collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>The resulting list would contain {@code "abc"}, {@code "def"},
+     * the empty string, and {@code "ghi"}.
+     *
+     * @return a sequential stream of token strings
+     * @throws IllegalStateException if this scanner is closed
+     * @since 9
+     */
+    public Stream<String> tokens() {
+        ensureOpen();
+        Stream<String> stream = StreamSupport.stream(new TokenSpliterator(), false);
+        return stream.onClose(this::close);
+    }
+
+    class TokenSpliterator extends Spliterators.AbstractSpliterator<String> {
+        int expectedCount = -1;
+
+        TokenSpliterator() {
+            super(Long.MAX_VALUE,
+                  Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super String> cons) {
+            if (expectedCount >= 0 && expectedCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+
+            if (hasNext()) {
+                String token = next();
+                expectedCount = modCount;
+                cons.accept(token);
+                if (expectedCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+                return true;
+            } else {
+                expectedCount = modCount;
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Returns a stream of match results from this scanner. The stream
+     * contains the same results in the same order that would be returned by
+     * calling {@code findWithinHorizon(pattern, 0)} and then {@link #match}
+     * successively as long as {@link #findWithinHorizon findWithinHorizon()}
+     * finds matches.
+     *
+     * <p>The resulting stream is sequential and ordered. All stream elements are
+     * non-null.
+     *
+     * <p>Scanning starts upon initiation of the terminal stream operation, using the
+     * current state of this scanner. Subsequent calls to any methods on this scanner
+     * other than {@link #close} and {@link #ioException} may return undefined results
+     * or may cause undefined effects on the returned stream. The returned stream's source
+     * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if any such calls are detected
+     * during stream pipeline execution.
+     *
+     * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
+     * state and cannot be reused.
+     *
+     * <p>If this scanner contains a resource that must be released, this scanner
+     * should be closed, either by calling its {@link #close} method, or by
+     * closing the returned stream. Closing the stream will close the underlying scanner.
+     * {@code IllegalStateException} is thrown if the scanner has been closed when this
+     * method is called, or if this scanner is closed during stream pipeline execution.
+     *
+     * <p>As with the {@link #findWithinHorizon findWithinHorizon()} methods, this method
+     * might block waiting for additional input, and it might buffer an unbounded amount of
+     * input searching for a match.
+     *
+     * @apiNote
+     * For example, the following code will read a file and return a list
+     * of all sequences of characters consisting of seven or more Latin capital
+     * letters:
+     *
+     * <pre>{@code
+     * try (Scanner sc = new Scanner(Path.of("input.txt"))) {
+     *     Pattern pat = Pattern.compile("[A-Z]{7,}");
+     *     List<String> capWords = sc.findAll(pat)
+     *                               .map(MatchResult::group)
+     *                               .collect(Collectors.toList());
+     * }
+     * }</pre>
+     *
+     * @param pattern the pattern to be matched
+     * @return a sequential stream of match results
+     * @throws NullPointerException if pattern is null
+     * @throws IllegalStateException if this scanner is closed
+     * @since 9
+     */
+    public Stream<MatchResult> findAll(Pattern pattern) {
+        Objects.requireNonNull(pattern);
+        ensureOpen();
+        Stream<MatchResult> stream = StreamSupport.stream(new FindSpliterator(pattern), false);
+        return stream.onClose(this::close);
+    }
+
+    /**
+     * Returns a stream of match results that match the provided pattern string.
+     * The effect is equivalent to the following code:
+     *
+     * <pre>{@code
+     *     scanner.findAll(Pattern.compile(patString))
+     * }</pre>
+     *
+     * @param patString the pattern string
+     * @return a sequential stream of match results
+     * @throws NullPointerException if patString is null
+     * @throws IllegalStateException if this scanner is closed
+     * @throws PatternSyntaxException if the regular expression's syntax is invalid
+     * @since 9
+     * @see java.util.regex.Pattern
+     */
+    public Stream<MatchResult> findAll(String patString) {
+        Objects.requireNonNull(patString);
+        ensureOpen();
+        return findAll(patternCache.forName(patString));
+    }
+
+    class FindSpliterator extends Spliterators.AbstractSpliterator<MatchResult> {
+        final Pattern pattern;
+        int expectedCount = -1;
+        private boolean advance = false; // true if we need to auto-advance
+
+        FindSpliterator(Pattern pattern) {
+            super(Long.MAX_VALUE,
+                  Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
+            this.pattern = pattern;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super MatchResult> cons) {
+            ensureOpen();
+            if (expectedCount >= 0) {
+                if (expectedCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            } else {
+                // init
+                matchValid = false;
+                matcher.usePattern(pattern);
+                expectedCount = modCount;
+            }
+
+            while (true) {
+                // assert expectedCount == modCount
+                if (nextInBuffer()) { // doesn't increment modCount
+                    cons.accept(matcher.toMatchResult());
+                    if (expectedCount != modCount) {
+                        throw new ConcurrentModificationException();
+                    }
+                    return true;
+                }
+                if (needInput)
+                    readInput(); // doesn't increment modCount
+                else
+                    return false; // reached end of input
+            }
+        }
+
+        // reimplementation of findPatternInBuffer with auto-advance on zero-length matches
+        private boolean nextInBuffer() {
+            if (advance) {
+                if (position + 1 > buf.limit()) {
+                    if (!sourceClosed)
+                        needInput = true;
+                    return false;
+                }
+                position++;
+                advance = false;
+            }
+            matcher.region(position, buf.limit());
+            if (matcher.find() && (!matcher.hitEnd() || sourceClosed)) {
+                 // Did not hit end, or hit real end
+                 position = matcher.end();
+                 advance = matcher.start() == position;
+                 return true;
+            }
+            if (!sourceClosed)
+                needInput = true;
+            return false;
+        }
+    }
+
+    /** Small LRU cache of Patterns. */
+    private static class PatternLRUCache {
+
+        private Pattern[] oa = null;
+        private final int size;
+
+        PatternLRUCache(int size) {
+            this.size = size;
+        }
+
+        boolean hasName(Pattern p, String s) {
+            return p.pattern().equals(s);
+        }
+
+        void moveToFront(Object[] oa, int i) {
+            Object ob = oa[i];
+            for (int j = i; j > 0; j--)
+                oa[j] = oa[j - 1];
+            oa[0] = ob;
+        }
+
+        Pattern forName(String name) {
+            if (oa == null) {
+                Pattern[] temp = new Pattern[size];
+                oa = temp;
+            } else {
+                for (int i = 0; i < oa.length; i++) {
+                    Pattern ob = oa[i];
+                    if (ob == null)
+                        continue;
+                    if (hasName(ob, name)) {
+                        if (i > 0)
+                            moveToFront(oa, i);
+                        return ob;
+                    }
+                }
+            }
+
+            // Create a new object
+            Pattern ob = Pattern.compile(name);
+            oa[oa.length - 1] = ob;
+            moveToFront(oa, oa.length - 1);
+            return ob;
+        }
+    }
+}
diff --git a/android-35/java/util/SequencedCollection.java b/android-35/java/util/SequencedCollection.java
new file mode 100644
index 0000000..54237c7
--- /dev/null
+++ b/android-35/java/util/SequencedCollection.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A collection that has a well-defined encounter order, that supports operations at both ends,
+ * and that is reversible. The elements of a sequenced collection have an <a id="encounter">
+ * <i>encounter order</i></a>, where conceptually the elements have a linear arrangement
+ * from the first element to the last element. Given any two elements, one element is
+ * either before (closer to the first element) or after (closer to the last element)
+ * the other element.
+ * <p>
+ * (Note that this definition does not imply anything about physical positioning
+ * of elements, such as their locations in a computer's memory.)
+ * <p>
+ * Several methods inherited from the {@link Collection} interface are required to operate
+ * on elements according to this collection's encounter order. For instance, the
+ * {@link Collection#iterator iterator} method provides elements starting from the first element,
+ * proceeding through successive elements, until the last element. Other methods that are
+ * required to operate on elements in encounter order include the following:
+ * {@link Iterable#forEach forEach}, {@link Collection#parallelStream parallelStream},
+ * {@link Collection#spliterator spliterator}, {@link Collection#stream stream},
+ * and all overloads of the {@link Collection#toArray toArray} method.
+ * <p>
+ * This interface provides methods to add, retrieve, and remove elements at either end
+ * of the collection.
+ * <p>
+ * This interface also defines the {@link #reversed reversed} method, which provides
+ * a reverse-ordered <a href="Collection.html#view">view</a> of this collection.
+ * In the reverse-ordered view, the concepts of first and last are inverted, as are
+ * the concepts of successor and predecessor. The first element of this collection is
+ * the last element of the reverse-ordered view, and vice-versa. The successor of some
+ * element in this collection is its predecessor in the reversed view, and vice-versa. All
+ * methods that respect the encounter order of the collection operate as if the encounter order
+ * is inverted. For instance, the {@link #iterator} method of the reversed view reports the
+ * elements in order from the last element of this collection to the first. The availability of
+ * the {@code reversed} method, and its impact on the ordering semantics of all applicable
+ * methods, allow convenient iteration, searching, copying, and streaming of the elements of
+ * this collection in either forward order or reverse order.
+ * <p>
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @apiNote
+ * This interface does not impose any requirements on the {@code equals} and {@code hashCode}
+ * methods, because requirements imposed by sub-interfaces {@link List} and {@link SequencedSet}
+ * (which inherits requirements from {@link Set}) would be in conflict. See the specifications for
+ * {@link Collection#equals Collection.equals} and {@link Collection#hashCode Collection.hashCode}
+ * for further information.
+ *
+ * @param <E> the type of elements in this collection
+ * @since 21
+ */
+public interface SequencedCollection<E> extends Collection<E> {
+    /**
+     * Returns a reverse-ordered <a href="Collection.html#view">view</a> of this collection.
+     * The encounter order of elements in the returned view is the inverse of the encounter
+     * order of elements in this collection. The reverse ordering affects all order-sensitive
+     * operations, including those on the view collections of the returned view. If the collection
+     * implementation permits modifications to this view, the modifications "write through" to the
+     * underlying collection. Changes to the underlying collection might or might not be visible
+     * in this reversed view, depending upon the implementation.
+     *
+     * @return a reverse-ordered view of this collection
+     */
+    SequencedCollection<E> reversed();
+
+    /**
+     * Adds an element as the first element of this collection (optional operation).
+     * After this operation completes normally, the given element will be a member of
+     * this collection, and it will be the first element in encounter order.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @param e the element to be added
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     * @throws UnsupportedOperationException if this collection implementation
+     *         does not support this operation
+     */
+    default void addFirst(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Adds an element as the last element of this collection (optional operation).
+     * After this operation completes normally, the given element will be a member of
+     * this collection, and it will be the last element in encounter order.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @param e the element to be added.
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     * @throws UnsupportedOperationException if this collection implementation
+     *         does not support this operation
+     */
+    default void addLast(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Gets the first element of this collection.
+     *
+     * @implSpec
+     * The implementation in this interface obtains an iterator of this collection, and
+     * then it obtains an element by calling the iterator's {@code next} method. Any
+     * {@code NoSuchElementException} thrown is propagated. Otherwise, it returns
+     * the element.
+     *
+     * @return the retrieved element
+     * @throws NoSuchElementException if this collection is empty
+     */
+    default E getFirst() {
+        return this.iterator().next();
+    }
+
+    /**
+     * Gets the last element of this collection.
+     *
+     * @implSpec
+     * The implementation in this interface obtains an iterator of the reversed view
+     * of this collection, and then it obtains an element by calling the iterator's
+     * {@code next} method. Any {@code NoSuchElementException} thrown is propagated.
+     * Otherwise, it returns the element.
+     *
+     * @return the retrieved element
+     * @throws NoSuchElementException if this collection is empty
+     */
+    default E getLast() {
+        return this.reversed().iterator().next();
+    }
+
+    /**
+     * Removes and returns the first element of this collection (optional operation).
+     *
+     * @implSpec
+     * The implementation in this interface obtains an iterator of this collection, and then
+     * it obtains an element by calling the iterator's {@code next} method. Any
+     * {@code NoSuchElementException} thrown is propagated. It then calls the iterator's
+     * {@code remove} method. Any {@code UnsupportedOperationException} thrown is propagated.
+     * Then, it returns the element.
+     *
+     * @return the removed element
+     * @throws NoSuchElementException if this collection is empty
+     * @throws UnsupportedOperationException if this collection implementation
+     *         does not support this operation
+     */
+    default E removeFirst() {
+        var it = this.iterator();
+        E e = it.next();
+        it.remove();
+        return e;
+    }
+
+    /**
+     * Removes and returns the last element of this collection (optional operation).
+     *
+     * @implSpec
+     * The implementation in this interface obtains an iterator of the reversed view of this
+     * collection, and then it obtains an element by calling the iterator's {@code next} method.
+     * Any {@code NoSuchElementException} thrown is propagated. It then calls the iterator's
+     * {@code remove} method. Any {@code UnsupportedOperationException} thrown is propagated.
+     * Then, it returns the element.
+     *
+     * @return the removed element
+     * @throws NoSuchElementException if this collection is empty
+     * @throws UnsupportedOperationException if this collection implementation
+     *         does not support this operation
+     */
+    default E removeLast() {
+        var it = this.reversed().iterator();
+        E e = it.next();
+        it.remove();
+        return e;
+    }
+}
diff --git a/android-35/java/util/SequencedMap.java b/android-35/java/util/SequencedMap.java
new file mode 100644
index 0000000..6bff204
--- /dev/null
+++ b/android-35/java/util/SequencedMap.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.util.NullableKeyValueHolder;
+
+/**
+ * A Map that has a well-defined encounter order, that supports operations at both ends, and
+ * that is reversible. The <a href="SequencedCollection.html#encounter">encounter order</a>
+ * of a {@code SequencedMap} is similar to that of the elements of a {@link SequencedCollection},
+ * but the ordering applies to mappings instead of individual elements.
+ * <p>
+ * The bulk operations on this map, including the {@link #forEach forEach} and the
+ * {@link #replaceAll replaceAll} methods, operate on this map's mappings in
+ * encounter order.
+ * <p>
+ * The view collections provided by the
+ * {@link #keySet keySet},
+ * {@link #values values},
+ * {@link #entrySet entrySet},
+ * {@link #sequencedKeySet sequencedKeySet},
+ * {@link #sequencedValues sequencedValues},
+ * and
+ * {@link #sequencedEntrySet sequencedEntrySet} methods all reflect the encounter order
+ * of this map. Even though the return values of the {@code keySet}, {@code values}, and
+ * {@code entrySet} methods are not sequenced <i>types</i>, the elements
+ * in those view collections do reflect the encounter order of this map. Thus, the
+ * iterators returned by the statements
+ * {@snippet :
+ *     var it1 = sequencedMap.entrySet().iterator();
+ *     var it2 = sequencedMap.sequencedEntrySet().iterator();
+ * }
+ * both provide the mappings of {@code sequencedMap} in that map's encounter order.
+ * <p>
+ * This interface provides methods to add mappings, to retrieve mappings, and to remove
+ * mappings at either end of the map's encounter order.
+ * <p>
+ * This interface also defines the {@link #reversed} method, which provides a
+ * reverse-ordered <a href="Collection.html#view">view</a> of this map.
+ * In the reverse-ordered view, the concepts of first and last are inverted, as
+ * are the concepts of successor and predecessor. The first mapping of this map
+ * is the last mapping of the reverse-ordered view, and vice-versa. The successor of some
+ * mapping in this map is its predecessor in the reversed view, and vice-versa. All
+ * methods that respect the encounter order of the map operate as if the encounter order
+ * is inverted. For instance, the {@link #forEach forEach} method of the reversed view reports
+ * the mappings in order from the last mapping of this map to the first. In addition, all of
+ * the view collections of the reversed view also reflect the inverse of this map's
+ * encounter order. For example,
+ * {@snippet :
+ *     var itr = sequencedMap.reversed().entrySet().iterator();
+ * }
+ * provides the mappings of this map in the inverse of the encounter order, that is, from
+ * the last mapping to the first mapping. The availability of the {@code reversed} method,
+ * and its impact on the ordering semantics of all applicable methods and views, allow convenient
+ * iteration, searching, copying, and streaming of this map's mappings in either forward order or
+ * reverse order.
+ * <p>
+ * A map's reverse-ordered view is generally not serializable, even if the original
+ * map is serializable.
+ * <p>
+ * The {@link Map.Entry} instances obtained by iterating the {@link #entrySet} view, the
+ * {@link #sequencedEntrySet} view, and its reverse-ordered view, maintain a connection to the
+ * underlying map. This connection is guaranteed only during the iteration. It is unspecified
+ * whether the connection is maintained outside of the iteration. If the underlying map permits
+ * it, calling an Entry's {@link Map.Entry#setValue setValue} method will modify the value of the
+ * underlying mapping. It is, however, unspecified whether modifications to the value in the
+ * underlying mapping are visible in the {@code Entry} instance.
+ * <p>
+ * The methods
+ * {@link #firstEntry},
+ * {@link #lastEntry},
+ * {@link #pollFirstEntry}, and
+ * {@link #pollLastEntry}
+ * return {@link Map.Entry} instances that represent snapshots of mappings as
+ * of the time of the call. They do <em>not</em> support mutation of the
+ * underlying map via the optional {@link Map.Entry#setValue setValue} method.
+ * <p>
+ * Depending upon the implementation, the {@code Entry} instances returned by other
+ * means might or might not be connected to the underlying map. For example, consider
+ * an {@code Entry} obtained in the following manner:
+ * {@snippet :
+ *     var entry = sequencedMap.sequencedEntrySet().getFirst();
+ * }
+ * It is not specified by this interface whether the {@code setValue} method of the
+ * {@code Entry} thus obtained will update a mapping in the underlying map, or whether
+ * it will throw an exception, or whether changes to the underlying map are visible in
+ * that {@code Entry}.
+ * <p>
+ * This interface has the same requirements on the {@code equals} and {@code hashCode}
+ * methods as defined by {@link Map#equals Map.equals} and {@link Map#hashCode Map.hashCode}.
+ * Thus, a {@code Map} and a {@code SequencedMap} will compare equals if and only
+ * if they have equal mappings, irrespective of ordering.
+ * <p>
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 21
+ */
+public interface SequencedMap<K, V> extends Map<K, V> {
+    /**
+     * Returns a reverse-ordered <a href="Collection.html#view">view</a> of this map.
+     * The encounter order of mappings in the returned view is the inverse of the encounter
+     * order of mappings in this map. The reverse ordering affects all order-sensitive operations,
+     * including those on the view collections of the returned view. If the implementation permits
+     * modifications to this view, the modifications "write through" to the underlying map.
+     * Changes to the underlying map might or might not be visible in this reversed view,
+     * depending upon the implementation.
+     *
+     * @return a reverse-ordered view of this map
+     */
+    SequencedMap<K, V> reversed();
+
+    /**
+     * Returns the first key-value mapping in this map,
+     * or {@code null} if the map is empty.
+     *
+     * @implSpec
+     * The implementation in this interface obtains the iterator of this map's entrySet.
+     * If the iterator has an element, it returns an unmodifiable copy of that element.
+     * Otherwise, it returns null.
+     *
+     * @return the first key-value mapping,
+     *         or {@code null} if this map is empty
+     */
+    default Map.Entry<K,V> firstEntry() {
+        var it = entrySet().iterator();
+        return it.hasNext() ? new NullableKeyValueHolder<>(it.next()) : null;
+    }
+
+    /**
+     * Returns the last key-value mapping in this map,
+     * or {@code null} if the map is empty.
+     *
+     * @implSpec
+     * The implementation in this interface obtains the iterator of the entrySet of this map's
+     * reversed view. If the iterator has an element, it returns an unmodifiable copy of
+     * that element. Otherwise, it returns null.
+     *
+     * @return the last key-value mapping,
+     *         or {@code null} if this map is empty
+     */
+    default Map.Entry<K,V> lastEntry() {
+        var it = reversed().entrySet().iterator();
+        return it.hasNext() ? new NullableKeyValueHolder<>(it.next()) : null;
+    }
+
+    /**
+     * Removes and returns the first key-value mapping in this map,
+     * or {@code null} if the map is empty (optional operation).
+     *
+     * @implSpec
+     * The implementation in this interface obtains the iterator of this map's entrySet.
+     * If the iterator has an element, it calls {@code remove} on the iterator and
+     * then returns an unmodifiable copy of that element. Otherwise, it returns null.
+     *
+     * @return the removed first entry of this map,
+     *         or {@code null} if this map is empty
+     * @throws UnsupportedOperationException if this collection implementation does not
+     *         support this operation
+     */
+    default Map.Entry<K,V> pollFirstEntry() {
+        var it = entrySet().iterator();
+        if (it.hasNext()) {
+            var entry = new NullableKeyValueHolder<>(it.next());
+            it.remove();
+            return entry;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Removes and returns the last key-value mapping in this map,
+     * or {@code null} if the map is empty (optional operation).
+     *
+     * @implSpec
+     * The implementation in this interface obtains the iterator of the entrySet of this map's
+     * reversed view. If the iterator has an element, it calls {@code remove} on the iterator
+     * and then returns an unmodifiable copy of that element. Otherwise, it returns null.
+     *
+     * @return the removed last entry of this map,
+     *         or {@code null} if this map is empty
+     * @throws UnsupportedOperationException if this collection implementation does not
+     *         support this operation
+     */
+    default Map.Entry<K,V> pollLastEntry() {
+        var it = reversed().entrySet().iterator();
+        if (it.hasNext()) {
+            var entry = new NullableKeyValueHolder<>(it.next());
+            it.remove();
+            return entry;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Inserts the given mapping into the map if it is not already present, or replaces the
+     * value of a mapping if it is already present (optional operation). After this operation
+     * completes normally, the given mapping will be present in this map, and it will be the
+     * first mapping in this map's encounter order.
+     *
+     * @implSpec The implementation in this interface always throws
+     * {@code UnsupportedOperationException}.
+     *
+     * @param k the key
+     * @param v the value
+     * @return the value previously associated with k, or null if none
+     * @throws UnsupportedOperationException if this collection implementation does not
+     *         support this operation
+     */
+    default V putFirst(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Inserts the given mapping into the map if it is not already present, or replaces the
+     * value of a mapping if it is already present (optional operation). After this operation
+     * completes normally, the given mapping will be present in this map, and it will be the
+     * last mapping in this map's encounter order.
+     *
+     * @implSpec The implementation in this interface always throws
+     * {@code UnsupportedOperationException}.
+     *
+     * @param k the key
+     * @param v the value
+     * @return the value previously associated with k, or null if none
+     * @throws UnsupportedOperationException if this collection implementation does not
+     *         support this operation
+     */
+    default V putLast(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a {@code SequencedSet} view of this map's {@link #keySet keySet}.
+     *
+     * @implSpec
+     * The implementation in this interface returns a {@code SequencedSet} instance
+     * that behaves as follows. Its {@link SequencedSet#add add} and {@link
+     * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}.
+     * Its {@link SequencedSet#reversed reversed} method returns the {@link
+     * #sequencedKeySet sequencedKeySet} view of the {@link #reversed reversed} view of
+     * this map. Each of its other methods calls the corresponding method of the {@link
+     * #keySet keySet} view of this map.
+     *
+     * @return a {@code SequencedSet} view of this map's {@code keySet}
+     */
+    default SequencedSet<K> sequencedKeySet() {
+        class SeqKeySet extends AbstractMap.ViewCollection<K> implements SequencedSet<K> {
+            Collection<K> view() {
+                return SequencedMap.this.keySet();
+            }
+            public SequencedSet<K> reversed() {
+                return SequencedMap.this.reversed().sequencedKeySet();
+            }
+            public boolean equals(Object other) {
+                return view().equals(other);
+            }
+            public int hashCode() {
+                return view().hashCode();
+            }
+        }
+        return new SeqKeySet();
+    }
+
+    /**
+     * Returns a {@code SequencedCollection} view of this map's {@link #values values} collection.
+     *
+     * @implSpec
+     * The implementation in this interface returns a {@code SequencedCollection} instance
+     * that behaves as follows. Its {@link SequencedCollection#add add} and {@link
+     * SequencedCollection#addAll addAll} methods throw {@link UnsupportedOperationException}.
+     * Its {@link SequencedCollection#reversed reversed} method returns the {@link
+     * #sequencedValues sequencedValues} view of the {@link #reversed reversed} view of
+     * this map. Its {@link Object#equals equals} and {@link Object#hashCode hashCode} methods
+     * are inherited from {@link Object}. Each of its other methods calls the corresponding
+     * method of the {@link #values values} view of this map.
+     *
+     * @return a {@code SequencedCollection} view of this map's {@code values} collection
+     */
+    default SequencedCollection<V> sequencedValues() {
+        class SeqValues extends AbstractMap.ViewCollection<V> implements SequencedCollection<V> {
+            Collection<V> view() {
+                return SequencedMap.this.values();
+            }
+            public SequencedCollection<V> reversed() {
+                return SequencedMap.this.reversed().sequencedValues();
+            }
+        }
+        return new SeqValues();
+    }
+
+    /**
+     * Returns a {@code SequencedSet} view of this map's {@link #entrySet entrySet}.
+     *
+     * @implSpec
+     * The implementation in this interface returns a {@code SequencedSet} instance
+     * that behaves as follows. Its {@link SequencedSet#add add} and {@link
+     * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}.
+     * Its {@link SequencedSet#reversed reversed} method returns the {@link
+     * #sequencedEntrySet sequencedEntrySet} view of the {@link #reversed reversed} view of
+     * this map. Each of its other methods calls the corresponding method of the {@link
+     * #entrySet entrySet} view of this map.
+     *
+     * @return a {@code SequencedSet} view of this map's {@code entrySet}
+     */
+    default SequencedSet<Map.Entry<K, V>> sequencedEntrySet() {
+        class SeqEntrySet extends AbstractMap.ViewCollection<Map.Entry<K, V>>
+                implements SequencedSet<Map.Entry<K, V>> {
+            Collection<Map.Entry<K, V>> view() {
+                return SequencedMap.this.entrySet();
+            }
+            public SequencedSet<Map.Entry<K, V>> reversed() {
+                return SequencedMap.this.reversed().sequencedEntrySet();
+            }
+            public boolean equals(Object other) {
+                return view().equals(other);
+            }
+            public int hashCode() {
+                return view().hashCode();
+            }
+        }
+        return new SeqEntrySet();
+    }
+}
diff --git a/android-35/java/util/SequencedSet.java b/android-35/java/util/SequencedSet.java
new file mode 100644
index 0000000..c02bfc1
--- /dev/null
+++ b/android-35/java/util/SequencedSet.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A collection that is both a {@link SequencedCollection} and a {@link Set}. As such,
+ * it can be thought of either as a {@code Set} that also has a well-defined
+ * <a href="SequencedCollection.html#encounter">encounter order</a>, or as a
+ * {@code SequencedCollection} that also has unique elements.
+ * <p>
+ * This interface has the same requirements on the {@code equals} and {@code hashCode}
+ * methods as defined by {@link Set#equals Set.equals} and {@link Set#hashCode Set.hashCode}.
+ * Thus, a {@code Set} and a {@code SequencedSet} will compare equals if and only
+ * if they have equal elements, irrespective of ordering.
+ * <p>
+ * {@code SequencedSet} defines the {@link #reversed} method, which provides a
+ * reverse-ordered <a href="Collection.html#view">view</a> of this set. The only difference
+ * from the {@link SequencedCollection#reversed SequencedCollection.reversed} method is
+ * that the return type of {@code SequencedSet.reversed} is {@code SequencedSet}.
+ * <p>
+ * This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements in this sequenced set
+ * @since 21
+ */
+public interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
+    /**
+     * {@inheritDoc}
+     *
+     * @return a reverse-ordered view of this collection, as a {@code SequencedSet}
+     */
+    SequencedSet<E> reversed();
+}
diff --git a/android-35/java/util/ServiceConfigurationError.java b/android-35/java/util/ServiceConfigurationError.java
new file mode 100644
index 0000000..0645f00
--- /dev/null
+++ b/android-35/java/util/ServiceConfigurationError.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+
+/**
+ * Error thrown when something goes wrong while locating, loading, or
+ * instantiating a service provider.
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ * @see ServiceLoader
+ */
+
+public class ServiceConfigurationError
+    extends Error
+{
+
+    @java.io.Serial
+    private static final long serialVersionUID = 74132770414881L;
+
+    /**
+     * Constructs a new instance with the specified message.
+     *
+     * @param  msg  The message, or {@code null} if there is no message
+     *
+     */
+    public ServiceConfigurationError(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance with the specified message and cause.
+     *
+     * @param  msg  The message, or {@code null} if there is no message
+     *
+     * @param  cause  The cause, or {@code null} if the cause is nonexistent
+     *                or unknown
+     */
+    public ServiceConfigurationError(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
diff --git a/android-35/java/util/ServiceLoader.java b/android-35/java/util/ServiceLoader.java
new file mode 100644
index 0000000..32329fb
--- /dev/null
+++ b/android-35/java/util/ServiceLoader.java
@@ -0,0 +1,1798 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.net.URLConnection;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.misc.VM;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+
+// Android-changed: JPMS and Security related sections are commented out.
+/**
+ * A facility to load implementations of a service.
+ *
+ * <p> A <i>service</i> is a well-known interface or class for which zero, one,
+ * or many service providers exist. A <i>service provider</i> (or just
+ * <i>provider</i>) is a class that implements or subclasses the well-known
+ * interface or class. A {@code ServiceLoader} is an object that locates and
+ * loads service providers deployed in the run time environment at a time of an
+ * application's choosing. Application code refers only to the service, not to
+ * service providers, and is assumed to be capable of choosing between multiple
+ * service providers (based on the functionality they expose through the service),
+ * and handling the possibility that no service providers are located.
+ *
+ * <h2> Obtaining a service loader </h2>
+ *
+ * <p> An application obtains a service loader for a given service by invoking
+ * one of the static {@code load} methods of {@code ServiceLoader}. <!--If the
+ * application is a module, then its module declaration must have a <i>uses</i>
+ * directive that specifies the service; this helps to locate providers and ensure
+ * they will execute reliably. In addition, if the application module does not
+ * contain the service, then its module declaration must have a <i>requires</i>
+ * directive that specifies the module which exports the service. It is strongly
+ * recommended that the application module does <b>not</b> require modules which
+ * contain providers of the service.--/>
+ *
+ * <p> A service loader can be used to locate and instantiate providers of the
+ * service by means of the {@link #iterator() iterator} method. {@code ServiceLoader}
+ * also defines the {@link #stream() stream} method to obtain a stream of providers
+ * that can be inspected and filtered without instantiating them.
+ *
+ * <p> As an example, suppose the service is {@code com.example.CodecFactory}, an
+ * interface that defines methods for producing encoders and decoders:
+ *
+ * <pre>{@code
+ *     package com.example;
+ *     public interface CodecFactory {
+ *         Encoder getEncoder(String encodingName);
+ *         Decoder getDecoder(String encodingName);
+ *     }
+ * }</pre>
+ *
+ * <p> The following code obtains a service loader for the {@code CodecFactory}
+ * service, then uses its iterator (created automatically by the enhanced-for
+ * loop) to yield instances of the service providers that are located:
+ *
+ * <pre>{@code
+ *     ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
+ *     for (CodecFactory factory : loader) {
+ *         Encoder enc = factory.getEncoder("PNG");
+ *         if (enc != null)
+ *             ... use enc to encode a PNG file
+ *             break;
+ *         }
+ * }</pre>
+ *
+ * <p> Sometimes an application may wish to inspect a service provider before
+ * instantiating it, in order to determine if an instance of that service
+ * provider would be useful. For example, a service provider for {@code
+ * CodecFactory} that is capable of producing a "PNG" encoder may be annotated
+ * with {@code @PNG}. The following code uses service loader's {@code stream}
+ * method to yield instances of {@code Provider<CodecFactory>} in contrast to
+ * how the iterator yields instances of {@code CodecFactory}:
+ * <pre>{@code
+ *     ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
+ *     Set<CodecFactory> pngFactories = loader
+ *            .stream()                                              // Note a below
+ *            .filter(p -> p.type().isAnnotationPresent(PNG.class))  // Note b
+ *            .map(Provider::get)                                    // Note c
+ *            .collect(Collectors.toSet());
+ * }</pre>
+ * <ol type="a">
+ *   <li> A stream of {@code Provider<CodecFactory>} objects </li>
+ *   <li> {@code p.type()} yields a {@code Class<CodecFactory>} </li>
+ *   <li> {@code get()} yields an instance of {@code CodecFactory} </li>
+ * </ol>
+ *
+ * <h2> Designing services </h2>
+ *
+ * <p> A service is a single type, usually an interface or abstract class. A
+ * concrete class can be used, but this is not recommended. The type may have
+ * any accessibility. The methods of a service are highly domain-specific, so
+ * this API specification cannot give concrete advice about their form or
+ * function. However, there are two general guidelines:
+ * <ol>
+ *   <li><p> A service should declare as many methods as needed to allow service
+ *   providers to communicate their domain-specific properties and other
+ *   quality-of-implementation factors. An application which obtains a service
+ *   loader for the service may then invoke these methods on each instance of
+ *   a service provider, in order to choose the best provider for the
+ *   application. </p></li>
+ *   <li><p> A service should express whether its service providers are intended
+ *   to be direct implementations of the service or to be an indirection
+ *   mechanism such as a "proxy" or a "factory". Service providers tend to be
+ *   indirection mechanisms when domain-specific objects are relatively
+ *   expensive to instantiate; in this case, the service should be designed
+ *   so that service providers are abstractions which create the "real"
+ *   implementation on demand. For example, the {@code CodecFactory} service
+ *   expresses through its name that its service providers are factories
+ *   for codecs, rather than codecs themselves, because it may be expensive
+ *   or complicated to produce certain codecs. </p></li>
+ * </ol>
+ *
+ * <h2> <a id="developing-service-providers">Developing service providers</a> </h2>
+ *
+ * <p> A service provider is a single type, usually a concrete class. An
+ * interface or abstract class is permitted because it may declare a static
+ * provider method, discussed later. The type must be public and must not be
+ * an inner class.
+ *
+ * <p> A service provider and its supporting code may be developed in a module,
+ * which is then deployed on the application module path or in a modular
+ * image. Alternatively, a service provider and its supporting code may be
+ * packaged as a JAR file and deployed on the application class path. The
+ * advantage of developing a service provider in a module is that the provider
+ * can be fully encapsulated to hide all details of its implementation.
+ *
+ * <p> An application that obtains a service loader for a given service is
+ * indifferent to whether providers of the service are deployed in modules or
+ * packaged as JAR files. The application instantiates service providers via
+ * the service loader's iterator, or via {@link Provider Provider} objects in
+ * the service loader's stream, without knowledge of the service providers'
+ * locations.
+ *
+ * <h2> Deploying service providers on the class path </h2>
+ *
+ * A service provider that is packaged as a JAR file for the class path is
+ * identified by placing a <i>provider-configuration file</i> in the resource
+ * directory {@code META-INF/services}. The name of the provider-configuration
+ * file is the fully qualified binary name of the service. The provider-configuration
+ * file contains a list of fully qualified binary names of service providers, one
+ * per line.
+ *
+ * <p> For example, suppose the service provider
+ * {@code com.example.impl.StandardCodecs} is packaged in a JAR file for the
+ * class path. The JAR file will contain a provider-configuration file named:
+ *
+ * <blockquote>{@code
+ *     META-INF/services/com.example.CodecFactory
+ * }</blockquote>
+ *
+ * that contains the line:
+ *
+ * <blockquote>{@code
+ *     com.example.impl.StandardCodecs # Standard codecs
+ * }</blockquote>
+ *
+ * <p><a id="format">The provider-configuration file must be encoded in UTF-8. </a>
+ * Space and tab characters surrounding each service provider's name, as well as
+ * blank lines, are ignored. The comment character is {@code '#'}
+ * ({@code U+0023} <span style="font-size:smaller;">NUMBER SIGN</span>);
+ * on each line all characters following the first comment character are ignored.
+ * If a service provider class name is listed more than once in a
+ * provider-configuration file then the duplicate is ignored. If a service
+ * provider class is named in more than one configuration file then the duplicate
+ * is ignored.
+ *
+ * <p> A service provider that is mentioned in a provider-configuration file may
+ * be located in the same JAR file as the provider-configuration file or in a
+ * different JAR file. The service provider must be visible from the class loader
+ * that is initially queried to locate the provider-configuration file; this is
+ * not necessarily the class loader which ultimately locates the
+ * provider-configuration file.
+ *
+ * <h2> Timing of provider discovery </h2>
+ *
+ * <p> Service providers are loaded and instantiated lazily, that is, on demand.
+ * A service loader maintains a cache of the providers that have been loaded so
+ * far. Each invocation of the {@code iterator} method returns an {@code Iterator}
+ * that first yields all of the elements cached from previous iteration, in
+ * instantiation order, and then lazily locates and instantiates any remaining
+ * providers, adding each one to the cache in turn. Similarly, each invocation
+ * of the stream method returns a {@code Stream} that first processes all
+ * providers loaded by previous stream operations, in load order, and then lazily
+ * locates any remaining providers. Caches are cleared via the {@link #reload
+ * reload} method.
+ *
+ * <h2> <a id="errors">Errors</a> </h2>
+ *
+ * <p> When using the service loader's {@code iterator}, the {@link
+ * Iterator#hasNext() hasNext} and {@link Iterator#next() next} methods will
+ * fail with {@link ServiceConfigurationError} if an error occurs locating,
+ * loading or instantiating a service provider. When processing the service
+ * loader's stream then {@code ServiceConfigurationError} may be thrown by any
+ * method that causes a service provider to be located or loaded.
+ *
+ * <p> When loading or instantiating a service provider in a module, {@code
+ * ServiceConfigurationError} can be thrown for the following reasons:
+ *
+ * <p> When reading a provider-configuration file, or loading or instantiating
+ * a provider class named in a provider-configuration file, then {@code
+ * ServiceConfigurationError} can be thrown for the following reasons:
+ *
+ * <ul>
+ *
+ *   <li> The format of the provider-configuration file violates the <a
+ *   href="ServiceLoader.html#format">format</a> specified above; </li>
+ *
+ *   <li> An {@link IOException IOException} occurs while reading the
+ *   provider-configuration file; </li>
+ *
+ *   <li> A service provider cannot be loaded; </li>
+ *
+ *   <li> A service provider is not assignable to the service's interface or
+ *   class, or does not define a provider constructor, or cannot be
+ *   instantiated. </li>
+ *
+ * </ul>
+ *
+ * <h2> Concurrency </h2>
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads.
+ *
+ * <h3> Null handling </h3>
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ * @param  <S>
+ *         The type of the service to be loaded by this loader
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ * @revised 9
+ */
+
+public final class ServiceLoader<S>
+    implements Iterable<S>
+{
+    // The class or interface representing the service being loaded
+    private final Class<S> service;
+
+    // The class of the service type
+    // Android-removed: used in JPMS paths only.
+    // private final String serviceName;
+
+    // Android-removed: JPMS is not supported.
+    // The module layer used to locate providers; null when locating
+    // providers using a class loader
+    // private final ModuleLayer layer;
+
+    // The class loader used to locate, load, and instantiate providers;
+    // null when locating provider using a module layer
+    private final ClassLoader loader;
+
+    // The access control context taken when the ServiceLoader is created
+    // Android-changed: do not use legacy security code.
+    // @SuppressWarnings("removal")
+    // private final AccessControlContext acc;
+
+    // The lazy-lookup iterator for iterator operations
+    private Iterator<Provider<S>> lookupIterator1;
+    private final List<S> instantiatedProviders = new ArrayList<>();
+
+    // The lazy-lookup iterator for stream operations
+    private Iterator<Provider<S>> lookupIterator2;
+    private final List<Provider<S>> loadedProviders = new ArrayList<>();
+    private boolean loadedAllProviders; // true when all providers loaded
+
+    // Incremented when reload is called
+    private int reloadCount;
+
+    // Android-removed: JavaLangAccess is not yet imported.
+    /*
+    private static JavaLangAccess LANG_ACCESS;
+    static {
+        LANG_ACCESS = SharedSecrets.getJavaLangAccess();
+    }
+    */
+
+    /**
+     * Represents a service provider located by {@code ServiceLoader}.
+     *
+     * <p> When using a loader's {@link ServiceLoader#stream() stream()} method
+     * then the elements are of type {@code Provider}. This allows processing
+     * to select or filter on the provider class without instantiating the
+     * provider. </p>
+     *
+     * @param  <S> The service type
+     * @since 9
+     */
+    public static interface Provider<S> extends Supplier<S> {
+        /**
+         * Returns the provider type. There is no guarantee that this type is
+         * accessible or that it has a public no-args constructor. The {@link
+         * #get() get()} method should be used to obtain the provider instance.
+         *
+         * <p> When a module declares that the provider class is created by a
+         * provider factory then this method returns the return type of its
+         * public static "{@code provider()}" method.
+         *
+         * @return The provider type
+         */
+        Class<? extends S> type();
+
+        /**
+         * Returns an instance of the provider.
+         *
+         * @return An instance of the provider.
+         *
+         * @throws ServiceConfigurationError
+         *         If the service provider cannot be instantiated, or in the
+         *         case of a provider factory, the public static
+         *         "{@code provider()}" method returns {@code null} or throws
+         *         an error or exception. The {@code ServiceConfigurationError}
+         *         will carry an appropriate cause where possible.
+         */
+        @Override S get();
+    }
+
+    // Android-removed: JPMS is not supported.
+    /*
+     * Initializes a new instance of this class for locating service providers
+     * in a module layer.
+     *
+     * @throws ServiceConfigurationError
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
+     *
+    @SuppressWarnings("removal")
+    private ServiceLoader(Class<?> caller, ModuleLayer layer, Class<S> svc) {
+        Objects.requireNonNull(caller);
+        Objects.requireNonNull(layer);
+        Objects.requireNonNull(svc);
+        checkCaller(caller, svc);
+
+        this.service = svc;
+        this.serviceName = svc.getName();
+        this.layer = layer;
+        this.loader = null;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
+    }
+    */
+
+    /**
+     * Initializes a new instance of this class for locating service providers
+     * via a class loader.
+     *
+     * @throws ServiceConfigurationError
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
+     */
+    @SuppressWarnings("removal")
+    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
+        Objects.requireNonNull(svc);
+
+        if (VM.isBooted()) {
+            checkCaller(caller, svc);
+            if (cl == null) {
+                cl = ClassLoader.getSystemClassLoader();
+            }
+        } else {
+
+            // if we get here then it means that ServiceLoader is being used
+            // before the VM initialization has completed. At this point then
+            // only code in the java.base should be executing.
+            // Android-removed: JPMS is not supported.
+            /*
+            Module callerModule = caller.getModule();
+            Module base = Object.class.getModule();
+            Module svcModule = svc.getModule();
+            if (callerModule != base || svcModule != base) {
+                fail(svc, "not accessible to " + callerModule + " during VM init");
+            }
+            */
+
+            // restricted to boot loader during startup
+            cl = null;
+        }
+
+        this.service = svc;
+        // Android-removed: used in JPMS paths only.
+        // this.serviceName = svc.getName();
+        // this.layer = null;
+        this.loader = cl;
+        // Android-removed: do not use legacy security code.
+        /*
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
+        */
+    }
+
+    // Android-removed: JPMS is not supported.
+    /*
+     * Initializes a new instance of this class for locating service providers
+     * via a class loader.
+     *
+     * @apiNote For use by ResourceBundle
+     *
+     * @throws ServiceConfigurationError
+     *         If the caller module does not use the service type.
+     *
+    @SuppressWarnings("removal")
+    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
+        }
+
+        this.service = Objects.requireNonNull(svc);
+        this.serviceName = svc.getName();
+        this.layer = null;
+        this.loader = cl;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
+    }
+    */
+
+    /**
+     * Checks that the given service type is accessible to types in the given
+     * module, and check that the module declares that it uses the service type.
+     */
+    private static void checkCaller(Class<?> caller, Class<?> svc) {
+        if (caller == null) {
+            fail(svc, "no caller to check if it declares `uses`");
+        }
+
+        // Check access to the service type
+        // Module callerModule = caller.getModule();
+        int mods = svc.getModifiers();
+        if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) {
+            // Android-removed: JPMS is not supported.
+            // fail(svc, "service type not accessible to " + callerModule);
+            fail(svc, "service type not accessible to " + caller);
+        }
+
+        // If the caller is in a named module then it should "uses" the
+        // service type
+        // Android-removed: JPMS is not supported.
+        /*
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
+        }
+        */
+    }
+
+    private static void fail(Class<?> service, String msg, Throwable cause)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg,
+                                            cause);
+    }
+
+    private static void fail(Class<?> service, String msg)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg);
+    }
+
+    private static void fail(Class<?> service, URL u, int line, String msg)
+        throws ServiceConfigurationError
+    {
+        fail(service, u + ":" + line + ": " + msg);
+    }
+
+    // Android-removed: JPMS is not supported.
+    /*
+     * Returns {@code true} if the provider is in an explicit module
+     *
+    private boolean inExplicitModule(Class<?> clazz) {
+        Module module = clazz.getModule();
+        return module.isNamed() && !module.getDescriptor().isAutomatic();
+    }
+    */
+
+    // Android-removed: used in JPMS paths only.
+    /*
+     * Returns the public static "provider" method if found.
+     *
+     * @throws ServiceConfigurationError if there is an error finding the
+     *         provider method or there is more than one public static
+     *         provider method
+     *
+    @SuppressWarnings("removal")
+    private Method findStaticProviderMethod(Class<?> clazz) {
+        List<Method> methods = null;
+        try {
+            methods = LANG_ACCESS.getDeclaredPublicMethods(clazz, "provider");
+        } catch (Throwable x) {
+            fail(service, "Unable to get public provider() method", x);
+        }
+        if (methods.isEmpty()) {
+            // does not declare a public provider method
+            return null;
+        }
+
+        // locate the static methods, can be at most one
+        Method result = null;
+        for (Method method : methods) {
+            int mods = method.getModifiers();
+            assert Modifier.isPublic(mods);
+            if (Modifier.isStatic(mods)) {
+                if (result != null) {
+                    fail(service, clazz + " declares more than one"
+                         + " public static provider() method");
+                }
+                result = method;
+            }
+        }
+        if (result != null) {
+            Method m = result;
+            PrivilegedAction<Void> pa = () -> {
+                m.setAccessible(true);
+                return null;
+            };
+            AccessController.doPrivileged(pa);
+        }
+        return result;
+    }
+    */
+
+    /**
+     * Returns the public no-arg constructor of a class.
+     *
+     * @throws ServiceConfigurationError if the class does not have
+     *         public no-arg constructor
+     */
+    @SuppressWarnings("removal")
+    private Constructor<?> getConstructor(Class<?> clazz) {
+        PrivilegedExceptionAction<Constructor<?>> pa
+            = new PrivilegedExceptionAction<>() {
+                @Override
+                public Constructor<?> run() throws Exception {
+                    Constructor<?> ctor = clazz.getConstructor();
+                    // Android-removed: JPMS is not supported.
+                    // if (inExplicitModule(clazz))
+                        ctor.setAccessible(true);
+                    return ctor;
+                }
+            };
+        Constructor<?> ctor = null;
+        try {
+            ctor = AccessController.doPrivileged(pa);
+        } catch (Throwable x) {
+            if (x instanceof PrivilegedActionException)
+                x = x.getCause();
+            String cn = clazz.getName();
+            fail(service, cn + " Unable to get public no-arg constructor", x);
+        }
+        return ctor;
+    }
+
+    /**
+     * A Provider implementation that supports invoking, with reduced
+     * permissions, the static factory to obtain the provider or the
+     * provider's no-arg constructor.
+     */
+    private static class ProviderImpl<S> implements Provider<S> {
+        final Class<S> service;
+        final Class<? extends S> type;
+        final Method factoryMethod;  // factory method or null
+        final Constructor<? extends S> ctor; // public no-args constructor or null
+        // BEGIN Android-changed: removed AccessControlContext from args list.
+        // ProviderImpl(Class, Class, Method) is not used, hence removed.
+        // @SuppressWarnings("removal")
+        // final AccessControlContext acc;
+
+        /*
+        ProviderImpl(Class<S> service,
+                     Class<? extends S> type,
+                     Method factoryMethod,
+                     @SuppressWarnings("removal") AccessControlContext acc) {
+            this.service = service;
+            this.type = type;
+            this.factoryMethod = factoryMethod;
+            this.ctor = null;
+            this.acc = acc;
+        }
+
+        ProviderImpl(Class<S> service,
+                     Class<? extends S> type,
+                     Constructor<? extends S> ctor,
+                     @SuppressWarnings("removal") AccessControlContext acc) {
+            this.service = service;
+            this.type = type;
+            this.factoryMethod = null;
+            this.ctor = ctor;
+            this.acc = acc;
+        }
+        */
+
+        ProviderImpl(Class<S> service,
+                Class<? extends S> type,
+                Constructor<? extends S> ctor) {
+            this.service = service;
+            this.type = type;
+            this.factoryMethod = null;
+            this.ctor = ctor;
+        }
+        // END Android-changed: removed AccessControlContext from args list.
+
+        @Override
+        public Class<? extends S> type() {
+            return type;
+        }
+
+        @Override
+        public S get() {
+            if (factoryMethod != null) {
+                return invokeFactoryMethod();
+            } else {
+                return newInstance();
+            }
+        }
+
+        /**
+         * Invokes the provider's "provider" method to instantiate a provider.
+         * When running with a security manager then the method runs with
+         * permissions that are restricted by the security context of whatever
+         * created this loader.
+         */
+        @SuppressWarnings("removal")
+        private S invokeFactoryMethod() {
+            Object result = null;
+            Throwable exc = null;
+            // BEGIN Android-changed: do not use legacy security code.
+            // if (acc == null) {
+                try {
+                    result = factoryMethod.invoke(null);
+                } catch (Throwable x) {
+                    exc = x;
+                }
+            /*
+            } else {
+                PrivilegedExceptionAction<?> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public Object run() throws Exception {
+                        return factoryMethod.invoke(null);
+                    }
+                };
+                // invoke factory method with permissions restricted by acc
+                try {
+                    result = AccessController.doPrivileged(pa, acc);
+                } catch (Throwable x) {
+                    if (x instanceof PrivilegedActionException)
+                        x = x.getCause();
+                    exc = x;
+                }
+            }
+            */
+            // END Android-changed: do not use legacy security code.
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                fail(service, factoryMethod + " failed", exc);
+            }
+            if (result == null) {
+                fail(service, factoryMethod + " returned null");
+            }
+            @SuppressWarnings("unchecked")
+            S p = (S) result;
+            return p;
+        }
+
+        /**
+         * Invokes Constructor::newInstance to instantiate a provider. When running
+         * with a security manager then the constructor runs with permissions that
+         * are restricted by the security context of whatever created this loader.
+         */
+        @SuppressWarnings("removal")
+        private S newInstance() {
+            S p = null;
+            Throwable exc = null;
+            // BEGIN Androic-changed: do not use legacy security code.
+            // if (acc == null) {
+                try {
+                    p = ctor.newInstance();
+                } catch (Throwable x) {
+                    exc = x;
+                }
+            /*
+            } else {
+                PrivilegedExceptionAction<S> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public S run() throws Exception {
+                        return ctor.newInstance();
+                    }
+                };
+                // invoke constructor with permissions restricted by acc
+                try {
+                    p = AccessController.doPrivileged(pa, acc);
+                } catch (Throwable x) {
+                    if (x instanceof PrivilegedActionException)
+                        x = x.getCause();
+                    exc = x;
+                }
+            }
+            */
+            // END Android-changed: do not use legacy security code.
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                String cn = ctor.getDeclaringClass().getName();
+                fail(service,
+                     "Provider " + cn + " could not be instantiated", exc);
+            }
+            return p;
+        }
+
+        // For now, equals/hashCode uses the access control context to ensure
+        // that two Providers created with different contexts are not equal
+        // when running with a security manager.
+
+        @Override
+        public int hashCode() {
+            // Android-changed: do not use legacy security code.
+            // return Objects.hash(service, type, acc);
+            return Objects.hash(service, type);
+        }
+
+        @Override
+        public boolean equals(Object ob) {
+            return ob instanceof @SuppressWarnings("unchecked")ProviderImpl<?> that
+                    && this.service == that.service
+                    && this.type == that.type;
+                    // Android-changed: do not use legacy security code.
+                    // && Objects.equals(this.acc, that.acc);
+        }
+    }
+
+    // BEGIN Android-removed: JPMS is not supported.
+    /*
+     * Loads a service provider in a module.
+     *
+     * Returns {@code null} if the service provider's module doesn't read
+     * the module with the service type.
+     *
+     * @throws ServiceConfigurationError if the class cannot be loaded or
+     *         isn't the expected sub-type (or doesn't define a provider
+     *         factory method that returns the expected type)
+     *
+    @SuppressWarnings("removal")
+    private Provider<S> loadProvider(ServiceProvider provider) {
+        Module module = provider.module();
+        if (!module.canRead(service.getModule())) {
+            // module does not read the module with the service type
+            return null;
+        }
+
+        String cn = provider.providerName();
+        Class<?> clazz = null;
+        if (acc == null) {
+            try {
+                clazz = Class.forName(module, cn);
+            } catch (LinkageError e) {
+                fail(service, "Unable to load " + cn, e);
+            }
+        } else {
+            PrivilegedExceptionAction<Class<?>> pa = () -> Class.forName(module, cn);
+            try {
+                clazz = AccessController.doPrivileged(pa);
+            } catch (Throwable x) {
+                if (x instanceof PrivilegedActionException)
+                    x = x.getCause();
+                fail(service, "Unable to load " + cn, x);
+                return null;
+            }
+        }
+        if (clazz == null) {
+            fail(service, "Provider " + cn + " not found");
+        }
+
+        int mods = clazz.getModifiers();
+        if (!Modifier.isPublic(mods)) {
+            fail(service, clazz + " is not public");
+        }
+
+        // if provider in explicit module then check for static factory method
+        if (inExplicitModule(clazz)) {
+            Method factoryMethod = findStaticProviderMethod(clazz);
+            if (factoryMethod != null) {
+                Class<?> returnType = factoryMethod.getReturnType();
+                if (!service.isAssignableFrom(returnType)) {
+                    fail(service, factoryMethod + " return type not a subtype");
+                }
+
+                @SuppressWarnings("unchecked")
+                Class<? extends S> type = (Class<? extends S>) returnType;
+                return new ProviderImpl<S>(service, type, factoryMethod, acc);
+            }
+        }
+
+        // no factory method so must be a subtype
+        if (!service.isAssignableFrom(clazz)) {
+            fail(service, clazz.getName() + " not a subtype");
+        }
+
+        @SuppressWarnings("unchecked")
+        Class<? extends S> type = (Class<? extends S>) clazz;
+        @SuppressWarnings("unchecked")
+        Constructor<? extends S> ctor = (Constructor<? extends S> ) getConstructor(clazz);
+        return new ProviderImpl<S>(service, type, ctor, acc);
+    }
+
+    /*
+     * Implements lazy service provider lookup of service providers that
+     * are provided by modules in a module layer (or parent layers)
+     *
+    private final class LayerLookupIterator<T>
+        implements Iterator<Provider<T>>
+    {
+        Deque<ModuleLayer> stack = new ArrayDeque<>();
+        Set<ModuleLayer> visited = new HashSet<>();
+        Iterator<ServiceProvider> iterator;
+
+        Provider<T> nextProvider;
+        ServiceConfigurationError nextError;
+
+        LayerLookupIterator() {
+            visited.add(layer);
+            stack.push(layer);
+        }
+
+        private Iterator<ServiceProvider> providers(ModuleLayer layer) {
+            ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer);
+            return catalog.findServices(serviceName).iterator();
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (nextProvider == null && nextError == null) {
+                // get next provider to load
+                while (iterator == null || !iterator.hasNext()) {
+                    // next layer (DFS order)
+                    if (stack.isEmpty())
+                        return false;
+
+                    ModuleLayer layer = stack.pop();
+                    List<ModuleLayer> parents = layer.parents();
+                    for (int i = parents.size() - 1; i >= 0; i--) {
+                        ModuleLayer parent = parents.get(i);
+                        if (visited.add(parent)) {
+                            stack.push(parent);
+                        }
+                    }
+                    iterator = providers(layer);
+                }
+
+                // attempt to load provider
+                ServiceProvider provider = iterator.next();
+                try {
+                    @SuppressWarnings("unchecked")
+                    Provider<T> next = (Provider<T>) loadProvider(provider);
+                    nextProvider = next;
+                } catch (ServiceConfigurationError e) {
+                    nextError = e;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public Provider<T> next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+
+            Provider<T> provider = nextProvider;
+            if (provider != null) {
+                nextProvider = null;
+                return provider;
+            } else {
+                ServiceConfigurationError e = nextError;
+                assert e != null;
+                nextError = null;
+                throw e;
+            }
+        }
+    }
+
+    /*
+     * Implements lazy service provider lookup of service providers that
+     * are provided by modules defined to a class loader or to modules in
+     * layers with a module defined to the class loader.
+     *
+    private final class ModuleServicesLookupIterator<T>
+        implements Iterator<Provider<T>>
+    {
+        ClassLoader currentLoader;
+        Iterator<ServiceProvider> iterator;
+
+        Provider<T> nextProvider;
+        ServiceConfigurationError nextError;
+
+        ModuleServicesLookupIterator() {
+            this.currentLoader = loader;
+            this.iterator = iteratorFor(loader);
+        }
+
+        /**
+         * Returns iterator to iterate over the implementations of {@code
+         * service} in the given layer.
+         *
+        private List<ServiceProvider> providers(ModuleLayer layer) {
+            ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer);
+            return catalog.findServices(serviceName);
+        }
+
+        /**
+         * Returns the class loader that a module is defined to
+         *
+        @SuppressWarnings("removal")
+        private ClassLoader loaderFor(Module module) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm == null) {
+                return module.getClassLoader();
+            } else {
+                PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+                return AccessController.doPrivileged(pa);
+            }
+        }
+
+        /**
+         * Returns an iterator to iterate over the implementations of {@code
+         * service} in modules defined to the given class loader or in custom
+         * layers with a module defined to this class loader.
+         *
+        private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
+            // modules defined to the class loader
+            ServicesCatalog catalog;
+            if (loader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
+            }
+            List<ServiceProvider> providers;
+            if (catalog == null) {
+                providers = List.of();
+            } else {
+                providers = catalog.findServices(serviceName);
+            }
+
+            // modules in layers that define modules to the class loader
+            ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
+            if (loader == null || loader == platformClassLoader) {
+                return providers.iterator();
+            } else {
+                List<ServiceProvider> allProviders = new ArrayList<>(providers);
+                Iterator<ModuleLayer> iterator = LANG_ACCESS.layers(loader).iterator();
+                while (iterator.hasNext()) {
+                    ModuleLayer layer = iterator.next();
+                    for (ServiceProvider sp : providers(layer)) {
+                        ClassLoader l = loaderFor(sp.module());
+                        if (l != null && l != platformClassLoader) {
+                            allProviders.add(sp);
+                        }
+                    }
+                }
+                return allProviders.iterator();
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (nextProvider == null && nextError == null) {
+                // get next provider to load
+                while (!iterator.hasNext()) {
+                    if (currentLoader == null) {
+                        return false;
+                    } else {
+                        currentLoader = currentLoader.getParent();
+                        iterator = iteratorFor(currentLoader);
+                    }
+                }
+
+                // attempt to load provider
+                ServiceProvider provider = iterator.next();
+                try {
+                    @SuppressWarnings("unchecked")
+                    Provider<T> next = (Provider<T>) loadProvider(provider);
+                    nextProvider = next;
+                } catch (ServiceConfigurationError e) {
+                    nextError = e;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public Provider<T> next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+
+            Provider<T> provider = nextProvider;
+            if (provider != null) {
+                nextProvider = null;
+                return provider;
+            } else {
+                ServiceConfigurationError e = nextError;
+                assert e != null;
+                nextError = null;
+                throw e;
+            }
+        }
+    }
+    */
+    // END Android-removed: JPMS is not supported.
+
+    /**
+     * Implements lazy service provider lookup where the service providers are
+     * configured via service configuration files. Service providers in named
+     * modules are silently ignored by this lookup iterator.
+     */
+    private final class LazyClassPathLookupIterator<T>
+        implements Iterator<Provider<T>>
+    {
+        static final String PREFIX = "META-INF/services/";
+
+        Set<String> providerNames = new HashSet<>();  // to avoid duplicates
+        Enumeration<URL> configs;
+        Iterator<String> pending;
+
+        Provider<T> nextProvider;
+        ServiceConfigurationError nextError;
+
+        LazyClassPathLookupIterator() { }
+
+        /**
+         * Parse a single line from the given configuration file, adding the
+         * name on the line to set of names if not already seen.
+         */
+        private int parseLine(URL u, BufferedReader r, int lc, Set<String> names)
+            throws IOException
+        {
+            String ln = r.readLine();
+            if (ln == null) {
+                return -1;
+            }
+            int ci = ln.indexOf('#');
+            if (ci >= 0) ln = ln.substring(0, ci);
+            ln = ln.trim();
+            int n = ln.length();
+            if (n != 0) {
+                if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+                    fail(service, u, lc, "Illegal configuration-file syntax");
+                int cp = ln.codePointAt(0);
+                if (!Character.isJavaIdentifierStart(cp))
+                    fail(service, u, lc, "Illegal provider-class name: " + ln);
+                int start = Character.charCount(cp);
+                for (int i = start; i < n; i += Character.charCount(cp)) {
+                    cp = ln.codePointAt(i);
+                    if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+                        fail(service, u, lc, "Illegal provider-class name: " + ln);
+                }
+                if (providerNames.add(ln)) {
+                    names.add(ln);
+                }
+            }
+            return lc + 1;
+        }
+
+        /**
+         * Parse the content of the given URL as a provider-configuration file.
+         */
+        private Iterator<String> parse(URL u) {
+            Set<String> names = new LinkedHashSet<>(); // preserve insertion order
+            try {
+                URLConnection uc = u.openConnection();
+                uc.setUseCaches(false);
+                try (InputStream in = uc.getInputStream();
+                     BufferedReader r
+                        // = new BufferedReader(new InputStreamReader(in, UTF_8.INSTANCE)))
+                        = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)))
+                {
+                    int lc = 1;
+                    while ((lc = parseLine(u, r, lc, names)) >= 0);
+                }
+            } catch (IOException x) {
+                fail(service, "Error accessing configuration file", x);
+            }
+            return names.iterator();
+        }
+
+        /**
+         * Loads and returns the next provider class.
+         */
+        private Class<?> nextProviderClass() {
+            if (configs == null) {
+                try {
+                    String fullName = PREFIX + service.getName();
+                    if (loader == null) {
+                        configs = ClassLoader.getSystemResources(fullName);
+                    // Android-removed: platformClassLoader not available on Android.
+                    // There were no changes in ClassLoaders, keeping old behaviour.
+                    /*
+                    } else if (loader == ClassLoaders.platformClassLoader()) {
+                        // The platform classloader doesn't have a class path,
+                        // but the boot loader might.
+                        if (BootLoader.hasClassPath()) {
+                            configs = BootLoader.findResources(fullName);
+                        } else {
+                            configs = Collections.emptyEnumeration();
+                        }
+                    */
+                    } else {
+                        configs = loader.getResources(fullName);
+                    }
+                } catch (IOException x) {
+                    fail(service, "Error locating configuration files", x);
+                }
+            }
+            while ((pending == null) || !pending.hasNext()) {
+                if (!configs.hasMoreElements()) {
+                    return null;
+                }
+                pending = parse(configs.nextElement());
+            }
+            String cn = pending.next();
+            try {
+                return Class.forName(cn, false, loader);
+            } catch (ClassNotFoundException x) {
+                // Android-changed: let the ServiceConfigurationError have a cause.
+                // fail(service, "Provider " + cn + " not found");
+                fail(service, "Provider " + cn + " not found", x);
+                return null;
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        private boolean hasNextService() {
+            while (nextProvider == null && nextError == null) {
+                try {
+                    Class<?> clazz = nextProviderClass();
+                    if (clazz == null)
+                        return false;
+
+                    // Android-removed: JPMS is not available on Android.
+                    /*
+                    if (clazz.getModule().isNamed()) {
+                        // ignore class if in named module
+                        continue;
+                    }
+                    */
+
+                    if (service.isAssignableFrom(clazz)) {
+                        Class<? extends S> type = (Class<? extends S>) clazz;
+                        Constructor<? extends S> ctor
+                            = (Constructor<? extends S>)getConstructor(clazz);
+                        // Android-changed: do not use legacy security code.
+                        // ProviderImpl<S> p = new ProviderImpl<S>(service, type, ctor, acc);
+                        ProviderImpl<S> p = new ProviderImpl<S>(service, type, ctor);
+                        nextProvider = (ProviderImpl<T>) p;
+                    } else {
+                        // Android-changed: Let the ServiceConfigurationError have a cause.
+                        // fail(service, clazz.getName() + " not a subtype");
+                        ClassCastException cce = new ClassCastException(
+                                service.getCanonicalName() + " is not assignable from " + clazz.getCanonicalName());
+                        fail(service, clazz.getName() + " not a subtype", cce);
+                    }
+                } catch (ServiceConfigurationError e) {
+                    nextError = e;
+                }
+            }
+            return true;
+        }
+
+        private Provider<T> nextService() {
+            if (!hasNextService())
+                throw new NoSuchElementException();
+            Provider<T> provider = nextProvider;
+            if (provider != null) {
+                nextProvider = null;
+                return provider;
+            } else {
+                ServiceConfigurationError e = nextError;
+                assert e != null;
+                nextError = null;
+                throw e;
+            }
+        }
+
+        @SuppressWarnings("removal")
+        @Override
+        public boolean hasNext() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return hasNextService();
+            /*
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        @SuppressWarnings("removal")
+        @Override
+        public Provider<T> next() {
+            // Android-changed: do not use legacy security code
+            // if (acc == null) {
+                return nextService();
+            /*
+            } else {
+                PrivilegedAction<Provider<T>> action = new PrivilegedAction<>() {
+                    public Provider<T> run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+    }
+
+    /**
+     * Returns a new lookup iterator.
+     */
+    private Iterator<Provider<S>> newLookupIterator() {
+        // Android-changed: JPMS is not supported, so there are no service defined in modules.
+        /*
+        assert layer == null || loader == null;
+        if (layer != null) {
+            return new LayerLookupIterator<>();
+        } else {
+            Iterator<Provider<S>> first = new ModuleServicesLookupIterator<>();
+            Iterator<Provider<S>> second = new LazyClassPathLookupIterator<>();
+            return new Iterator<Provider<S>>() {
+                @Override
+                public boolean hasNext() {
+                    return (first.hasNext() || second.hasNext());
+                }
+                @Override
+                public Provider<S> next() {
+                    if (first.hasNext()) {
+                        return first.next();
+                    } else if (second.hasNext()) {
+                        return second.next();
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+        */
+        return new LazyClassPathLookupIterator<>();
+    }
+
+    /**
+     * Returns an iterator to lazily load and instantiate the available
+     * providers of this loader's service.
+     *
+     * <p> To achieve laziness the actual work of locating and instantiating
+     * providers is done by the iterator itself. Its {@link Iterator#hasNext
+     * hasNext} and {@link Iterator#next next} methods can therefore throw a
+     * {@link ServiceConfigurationError} for any of the reasons specified in
+     * the <a href="#errors">Errors</a> section above. To write robust code it
+     * is only necessary to catch {@code ServiceConfigurationError} when using
+     * the iterator. If an error is thrown then subsequent invocations of the
+     * iterator will make a best effort to locate and instantiate the next
+     * available provider, but in general such recovery cannot be guaranteed.
+     *
+     * <p> Caching: The iterator returned by this method first yields all of
+     * the elements of the provider cache, in the order that they were loaded.
+     * It then lazily loads and instantiates any remaining service providers,
+     * adding each one to the cache in turn. If this loader's provider caches are
+     * cleared by invoking the {@link #reload() reload} method then existing
+     * iterators for this service loader should be discarded.
+     * The {@code  hasNext} and {@code next} methods of the iterator throw {@link
+     * java.util.ConcurrentModificationException ConcurrentModificationException}
+     * if used after the provider cache has been cleared.
+     *
+     * <p> The iterator returned by this method does not support removal.
+     * Invoking its {@link java.util.Iterator#remove() remove} method will
+     * cause an {@link UnsupportedOperationException} to be thrown.
+     *
+     * @apiNote Throwing an error in these cases may seem extreme.  The rationale
+     * for this behavior is that a malformed provider-configuration file, like a
+     * malformed class file, indicates a serious problem with the way the Java
+     * virtual machine is configured or is being used.  As such it is preferable
+     * to throw an error rather than try to recover or, even worse, fail silently.
+     *
+     * @return  An iterator that lazily loads providers for this loader's
+     *          service
+     *
+     * @revised 9
+     */
+    public Iterator<S> iterator() {
+
+        // create lookup iterator if needed
+        if (lookupIterator1 == null) {
+            lookupIterator1 = newLookupIterator();
+        }
+
+        return new Iterator<S>() {
+
+            // record reload count
+            final int expectedReloadCount = ServiceLoader.this.reloadCount;
+
+            // index into the cached providers list
+            int index;
+
+            /**
+             * Throws ConcurrentModificationException if the list of cached
+             * providers has been cleared by reload.
+             */
+            private void checkReloadCount() {
+                if (ServiceLoader.this.reloadCount != expectedReloadCount)
+                    throw new ConcurrentModificationException();
+            }
+
+            @Override
+            public boolean hasNext() {
+                checkReloadCount();
+                if (index < instantiatedProviders.size())
+                    return true;
+                return lookupIterator1.hasNext();
+            }
+
+            @Override
+            public S next() {
+                checkReloadCount();
+                S next;
+                if (index < instantiatedProviders.size()) {
+                    next = instantiatedProviders.get(index);
+                } else {
+                    next = lookupIterator1.next().get();
+                    instantiatedProviders.add(next);
+                }
+                index++;
+                return next;
+            }
+
+        };
+    }
+
+    /**
+     * Returns a stream to lazily load available providers of this loader's
+     * service. The stream elements are of type {@link Provider Provider}, the
+     * {@code Provider}'s {@link Provider#get() get} method must be invoked to
+     * get or instantiate the provider.
+     *
+     * <p> To achieve laziness the actual work of locating providers is done
+     * when processing the stream. If a service provider cannot be loaded for any
+     * of the reasons specified in the <a href="#errors">Errors</a> section
+     * above then {@link ServiceConfigurationError} is thrown by whatever method
+     * caused the service provider to be loaded. </p>
+     *
+     * <p> Caching: When processing the stream then providers that were previously
+     * loaded by stream operations are processed first, in load order. It then
+     * lazily loads any remaining service providers. If this loader's provider
+     * caches are cleared by invoking the {@link #reload() reload} method then
+     * existing streams for this service loader should be discarded. The returned
+     * stream's source {@link Spliterator spliterator} is <em>fail-fast</em> and
+     * will throw {@link ConcurrentModificationException} if the provider cache
+     * has been cleared. </p>
+     *
+     * <p> The following examples demonstrate usage. The first example creates
+     * a stream of {@code CodecFactory} objects, the second example is the same
+     * except that it sorts the providers by provider class name (and so locate
+     * all providers).
+     * <pre>{@code
+     *    Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
+     *            .stream()
+     *            .map(Provider::get);
+     *
+     *    Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
+     *            .stream()
+     *            .sorted(Comparator.comparing(p -> p.type().getName()))
+     *            .map(Provider::get);
+     * }</pre>
+     *
+     * @return  A stream that lazily loads providers for this loader's service
+     *
+     * @since 9
+     */
+    public Stream<Provider<S>> stream() {
+        // use cached providers as the source when all providers loaded
+        if (loadedAllProviders) {
+            return loadedProviders.stream();
+        }
+
+        // create lookup iterator if needed
+        if (lookupIterator2 == null) {
+            lookupIterator2 = newLookupIterator();
+        }
+
+        // use lookup iterator and cached providers as source
+        Spliterator<Provider<S>> s = new ProviderSpliterator<>(lookupIterator2);
+        return StreamSupport.stream(s, false);
+    }
+
+    private class ProviderSpliterator<T> implements Spliterator<Provider<T>> {
+        final int expectedReloadCount = ServiceLoader.this.reloadCount;
+        final Iterator<Provider<T>> iterator;
+        int index;
+
+        ProviderSpliterator(Iterator<Provider<T>> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        public Spliterator<Provider<T>> trySplit() {
+            return null;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super Provider<T>> action) {
+            if (ServiceLoader.this.reloadCount != expectedReloadCount)
+                throw new ConcurrentModificationException();
+            Provider<T> next = null;
+            if (index < loadedProviders.size()) {
+                next = (Provider<T>) loadedProviders.get(index++);
+            } else if (iterator.hasNext()) {
+                next = iterator.next();
+                loadedProviders.add((Provider<S>)next);
+                index++;
+            } else {
+                loadedAllProviders = true;
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            // not IMMUTABLE as structural interference possible
+            // not NOTNULL so that the characteristics are a subset of the
+            // characteristics when all Providers have been located.
+            return Spliterator.ORDERED;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+
+    // Android-removed: JPMS is not supported.
+    /*
+     * Creates a new service loader for the given service type, class
+     * loader, and caller.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @param  loader
+     *         The class loader to be used to load provider-configuration files
+     *         and provider classes, or {@code null} if the system class
+     *         loader (or, failing that, the bootstrap class loader) is to be
+     *         used
+     *
+     * @param  callerModule
+     *         The caller's module for which a new service loader is created
+     *
+     * @return A new service loader
+     *
+    static <S> ServiceLoader<S> load(Class<S> service,
+                                     ClassLoader loader,
+                                     Module callerModule)
+    {
+        return new ServiceLoader<>(callerModule, service, loader);
+    }
+    */
+
+    // Android-changed: removed module mentions.
+    /**
+     * Creates a new service loader for the given service. The service loader
+     * uses the given class loader as the starting point to locate service
+     * providers for the service.
+     *
+     * @apiNote If the class path of the class loader includes remote network
+     * URLs then those URLs may be dereferenced in the process of searching for
+     * provider-configuration files.
+     *
+     * <p> This activity is normal, although it may cause puzzling entries to be
+     * created in web-server logs.  If a web server is not configured correctly,
+     * however, then this activity may cause the provider-loading algorithm to fail
+     * spuriously.
+     *
+     * <p> A web server should return an HTTP 404 (Not Found) response when a
+     * requested resource does not exist.  Sometimes, however, web servers are
+     * erroneously configured to return an HTTP 200 (OK) response along with a
+     * helpful HTML error page in such cases.  This will cause a {@link
+     * ServiceConfigurationError} to be thrown when this class attempts to parse
+     * the HTML page as a provider-configuration file.  The best solution to this
+     * problem is to fix the misconfigured web server to return the correct
+     * response code (HTTP 404) along with the HTML error page.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @param  loader
+     *         The class loader to be used to load provider-configuration files
+     *         and provider classes, or {@code null} if the system class
+     *         loader (or, failing that, the bootstrap class loader) is to be
+     *         used
+     *
+     * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller <!-- or the
+     *         caller is in an explicit module and its module descriptor does
+     *         not declare that it uses {@code service} --/>
+     *
+     * @revised 9
+     */
+    @CallerSensitive
+    public static <S> ServiceLoader<S> load(Class<S> service,
+                                            ClassLoader loader)
+    {
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
+    }
+
+    // Android-changed: removed module mentions.
+    /**
+     * Creates a new service loader for the given service type, using the
+     * current thread's {@linkplain java.lang.Thread#getContextClassLoader
+     * context class loader}.
+     *
+     * <p> An invocation of this convenience method of the form
+     * <pre>{@code
+     *     ServiceLoader.load(service)
+     * }</pre>
+     *
+     * is equivalent to
+     *
+     * <pre>{@code
+     *     ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
+     * }</pre>
+     *
+     * @apiNote Service loader objects obtained with this method should not be
+     * cached VM-wide. For example, different applications in the same VM may
+     * have different thread context class loaders. A lookup by one application
+     * may locate a service provider that is only visible via its thread
+     * context class loader and so is not suitable to be located by the other
+     * application. Memory leaks can also arise. A thread local may be suited
+     * to some applications.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller
+     *
+     * @revised 9
+     */
+    @CallerSensitive
+    public static <S> ServiceLoader<S> load(Class<S> service) {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
+    }
+
+    // Android-changed: module and platformClassLoader mentions removed.
+    /**
+     * Creates a new service loader for the given service type, using the
+     * extension class loader.
+     *
+     * <p>This convenience method simply locates the extension class loader,
+     * call it {@code extClassLoader}, and then returns
+     *
+     * <pre>{@code
+     *     ServiceLoader.load(service, extClassLoader)
+     * }</pre>
+     *
+     * <p> This method is intended for use when only installed providers are
+     * desired.  The resulting service will only find and load providers that
+     * have been installed into the current Java virtual machine.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller
+     *
+     * @revised 9
+     */
+    @CallerSensitive
+    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
+        // Android-changed: there is no platformClassLoader, using extension classloader.
+        // ClassLoader cl = ClassLoader.getPlatformClassLoader();
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        ClassLoader prev = null;
+        while (cl != null) {
+            prev = cl;
+            cl = cl.getParent();
+        }
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, prev);
+    }
+
+    // Android-removed: JPMS is not supported.
+    /*
+     * Creates a new service loader for the given service type to load service
+     * providers from modules in the given module layer and its ancestors. It
+     * does not locate providers in unnamed modules. The ordering that the service
+     * loader's {@link #iterator() iterator} and {@link #stream() stream} locate
+     * providers and yield elements is as follows:
+     *
+     * <ul>
+     *   <li><p> Providers are located in a module layer before locating providers
+     *   in parent layers. Traversal of parent layers is depth-first with each
+     *   layer visited at most once. For example, suppose L0 is the boot layer, L1
+     *   and L2 are modules layers with L0 as their parent. Now suppose that L3 is
+     *   created with L1 and L2 as the parents (in that order). Using a service
+     *   loader to locate providers with L3 as the context will locate providers
+     *   in the following order: L3, L1, L0, L2. </p></li>
+     *
+     *   <li><p> If a module declares more than one provider then the providers
+     *   are located in the order that its module descriptor
+     *   {@linkplain java.lang.module.ModuleDescriptor.Provides#providers()
+     *   lists the providers}. Providers added dynamically by instrumentation
+     *   agents are always located after providers declared by the module. </p></li>
+     *
+     *   <li><p> The ordering of modules in a module layer is not defined. </p></li>
+     * </ul>
+     *
+     * @apiNote Unlike the other load methods defined here, the service type
+     * is the second parameter. The reason for this is to avoid source
+     * compatibility issues for code that uses {@code load(S, null)}.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  layer
+     *         The module layer
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     *
+     * @throws ServiceConfigurationError
+     *         if the service type is not accessible to the caller or the
+     *         caller is in an explicit module and its module descriptor does
+     *         not declare that it uses {@code service}
+     *
+     * @since 9
+     *
+    @CallerSensitive
+    public static <S> ServiceLoader<S> load(ModuleLayer layer, Class<S> service) {
+        return new ServiceLoader<>(Reflection.getCallerClass(), layer, service);
+    }
+    */
+
+    /**
+     * Load the first available service provider of this loader's service. This
+     * convenience method is equivalent to invoking the {@link #iterator()
+     * iterator()} method and obtaining the first element. It therefore
+     * returns the first element from the provider cache if possible, it
+     * otherwise attempts to load and instantiate the first provider.
+     *
+     * <p> The following example loads the first available service provider. If
+     * no service providers are located then it uses a default implementation.
+     * <pre>{@code
+     *    CodecFactory factory = ServiceLoader.load(CodecFactory.class)
+     *                                        .findFirst()
+     *                                        .orElse(DEFAULT_CODECSET_FACTORY);
+     * }</pre>
+     * @return The first service provider or empty {@code Optional} if no
+     *         service providers are located
+     *
+     * @throws ServiceConfigurationError
+     *         If a provider class cannot be loaded for any of the reasons
+     *         specified in the <a href="#errors">Errors</a> section above.
+     *
+     * @since 9
+     */
+    public Optional<S> findFirst() {
+        Iterator<S> iterator = iterator();
+        if (iterator.hasNext()) {
+            return Optional.of(iterator.next());
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Clear this loader's provider cache so that all providers will be
+     * reloaded.
+     *
+     * <p> After invoking this method, subsequent invocations of the {@link
+     * #iterator() iterator} or {@link #stream() stream} methods will lazily
+     * locate providers (and instantiate in the case of {@code iterator})
+     * from scratch, just as is done by a newly-created service loader.
+     *
+     * <p> This method is intended for use in situations in which new service
+     * providers can be installed into a running Java virtual machine.
+     */
+    public void reload() {
+        lookupIterator1 = null;
+        instantiatedProviders.clear();
+
+        lookupIterator2 = null;
+        loadedProviders.clear();
+        loadedAllProviders = false;
+
+        // increment count to allow CME be thrown
+        reloadCount++;
+    }
+
+    // BEGIN Android-added: loadFromSystemProperty(), for internal use.
+    // Instantiates a class from a system property (used elsewhere in libcore).
+    /**
+     * Internal API to support built-in SPIs that check a system property first.
+     * Returns an instance specified by a property with the class' binary name, or null if
+     * no such property is set.
+     * @hide
+     */
+    public static <S> S loadFromSystemProperty(final Class<S> service) {
+        try {
+            final String className = System.getProperty(service.getName());
+            if (className != null) {
+                Class<?> c = ClassLoader.getSystemClassLoader().loadClass(className);
+                return (S) c.newInstance();
+            }
+            return null;
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+    // END Android-added: loadFromSystemProperty(), for internal use.
+
+    /**
+     * Returns a string describing this service.
+     *
+     * @return  A descriptive string
+     */
+    public String toString() {
+        return "java.util.ServiceLoader[" + service.getName() + "]";
+    }
+
+}
diff --git a/android-35/java/util/Set.java b/android-35/java/util/Set.java
new file mode 100644
index 0000000..4c70300
--- /dev/null
+++ b/android-35/java/util/Set.java
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A collection that contains no duplicate elements.  More formally, sets
+ * contain no pair of elements {@code e1} and {@code e2} such that
+ * {@code e1.equals(e2)}, and at most one null element.  As implied by
+ * its name, this interface models the mathematical <i>set</i> abstraction.
+ *
+ * <p>The {@code Set} interface places additional stipulations, beyond those
+ * inherited from the {@code Collection} interface, on the contracts of all
+ * constructors and on the contracts of the {@code add}, {@code equals} and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.  (The specifications accompanying these
+ * declarations have been tailored to the {@code Set} interface, but they do
+ * not contain any additional stipulations.)
+ *
+ * <p>The additional stipulation on constructors is, not surprisingly,
+ * that all constructors must create a set that contains no duplicate elements
+ * (as defined above).
+ *
+ * <p>Note: Great care must be exercised if mutable objects are used as set
+ * elements.  The behavior of a set is not specified if the value of an object
+ * is changed in a manner that affects {@code equals} comparisons while the
+ * object is an element in the set.  A special case of this prohibition is
+ * that it is not permissible for a set to contain itself as an element.
+ *
+ * <p>Some set implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the set may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="unmodifiable">Unmodifiable Sets</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of} and
+ * {@link Set#copyOf Set.copyOf} static factory methods
+ * provide a convenient way to create unmodifiable sets. The {@code Set}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
+ * be added or removed. Calling any mutator method on the Set
+ * will always cause {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable, this may cause the
+ * Set to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>They reject duplicate elements at creation time. Duplicate elements
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of set elements is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions
+ * about the identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see SortedSet
+ * @see HashSet
+ * @see TreeSet
+ * @see AbstractSet
+ * @see Collections#singleton(java.lang.Object)
+ * @see Collections#EMPTY_SET
+ * @since 1.2
+ */
+
+public interface Set<E> extends Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this set (its cardinality).  If this
+     * set contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements are
+     * returned in no particular order (unless this set is an instance of some
+     * class that provides a guarantee).
+     *
+     * @return an iterator over the elements in this set
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present
+     * (optional operation).  More formally, adds the specified element
+     * {@code e} to this set if the set contains no element {@code e2}
+     * such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.  In combination with the
+     * restriction on constructors, this ensures that sets never contain
+     * duplicate elements.
+     *
+     * <p>The stipulation above does not imply that sets must accept all
+     * elements; sets may refuse to add any particular element, including
+     * {@code null}, and throw an exception, as described in the
+     * specification for {@link Collection#add Collection.add}.
+     * Individual set implementations should clearly document any
+     * restrictions on the elements that they may contain.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this set
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified element
+     *         prevents it from being added to this set
+     */
+    boolean add(E e);
+
+
+    /**
+     * Removes the specified element from this set if it is present
+     * (optional operation).  More formally, removes an element {@code e}
+     * such that
+     * {@code Objects.equals(o, e)}, if
+     * this set contains such an element.  Returns {@code true} if this set
+     * contained the element (or equivalently, if this set changed as a
+     * result of the call).  (This set will not contain the element once the
+     * call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this set
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present (optional operation).  If the specified
+     * collection is also a set, the {@code addAll} operation effectively
+     * modifies this set so that its value is the <i>union</i> of the two
+     * sets.  The behavior of this operation is undefined if the specified
+     * collection is modified while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     *
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of the
+     *         specified collection prevents it from being added to this set
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this set
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this set all of its elements that are not contained in the
+     * specified collection.  If the specified collection is also a set, this
+     * operation effectively modifies this set so that its value is the
+     * <i>intersection</i> of the two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this set (optional operation).
+     * The set will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} method
+     *         is not supported by this set
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT);
+    }
+
+    /**
+     * Returns an unmodifiable set containing zero elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @return an empty {@code Set}
+     *
+     * @since 9
+     */
+    @SuppressWarnings("unchecked")
+    static <E> Set<E> of() {
+        return (Set<E>) ImmutableCollections.EMPTY_SET;
+    }
+
+    /**
+     * Returns an unmodifiable set containing one element.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the single element
+     * @return a {@code Set} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1) {
+        return new ImmutableCollections.Set12<>(e1);
+    }
+
+    /**
+     * Returns an unmodifiable set containing two elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if the elements are duplicates
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2) {
+        return new ImmutableCollections.Set12<>(e1, e2);
+    }
+
+    /**
+     * Returns an unmodifiable set containing three elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an unmodifiable set containing four elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an unmodifiable set containing five elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an unmodifiable set containing six elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6);
+    }
+
+    /**
+     * Returns an unmodifiable set containing seven elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7);
+    }
+
+    /**
+     * Returns an unmodifiable set containing eight elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8);
+    }
+
+    /**
+     * Returns an unmodifiable set containing nine elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an unmodifiable set containing ten elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an unmodifiable set containing an arbitrary number of elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting set will be the component type of the array, and the size of
+     * the set will be equal to the length of the array. To create a set with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     Set<String[]> list = Set.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link Set#of(Object) Set.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param elements the elements to be contained in the set
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> Set<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                @SuppressWarnings("unchecked")
+                var set = (Set<E>) ImmutableCollections.EMPTY_SET;
+                return set;
+            case 1:
+                return new ImmutableCollections.Set12<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.Set12<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.SetN<>(elements);
+        }
+    }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable Set</a> containing the elements
+     * of the given Collection. The given Collection must not be null, and it must not
+     * contain any null elements. If the given Collection contains duplicate elements,
+     * an arbitrary element of the duplicates is preserved. If the given Collection is
+     * subsequently modified, the returned Set will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Collection is an <a href="#unmodifiable">unmodifiable Set</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param coll a {@code Collection} from which elements are drawn, must be non-null
+     * @return a {@code Set} containing the elements of the given {@code Collection}
+     * @throws NullPointerException if coll is null, or if it contains any nulls
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    static <E> Set<E> copyOf(Collection<? extends E> coll) {
+        if (coll instanceof ImmutableCollections.AbstractImmutableSet) {
+            return (Set<E>)coll;
+        } else {
+            return (Set<E>)Set.of(new HashSet<>(coll).toArray());
+        }
+    }
+}
diff --git a/android-35/java/util/SimpleTimeZone.java b/android-35/java/util/SimpleTimeZone.java
new file mode 100644
index 0000000..72ce744
--- /dev/null
+++ b/android-35/java/util/SimpleTimeZone.java
@@ -0,0 +1,1696 @@
+/*
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.Gregorian;
+
+/**
+ * {@code SimpleTimeZone} is a concrete subclass of {@code TimeZone}
+ * that represents a time zone for use with a Gregorian calendar.
+ * The class holds an offset from GMT, called <em>raw offset</em>, and start
+ * and end rules for a daylight saving time schedule.  Since it only holds
+ * single values for each, it cannot handle historical changes in the offset
+ * from GMT and the daylight saving schedule, except that the {@link
+ * #setStartYear setStartYear} method can specify the year when the daylight
+ * saving time schedule starts in effect.
+ * <p>
+ * To construct a {@code SimpleTimeZone} with a daylight saving time
+ * schedule, the schedule can be described with a set of rules,
+ * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
+ * starts or ends is specified by a combination of <em>month</em>,
+ * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
+ * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
+ * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
+ * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
+ * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
+ * are as follows.
+ *
+ * <ul>
+ * <li><b>Exact day of month</b><br>
+ * To specify an exact day of month, set the <em>month</em> and
+ * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
+ * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
+ * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
+ *
+ * <li><b>Day of week on or after day of month</b><br>
+ * To specify a day of week on or after an exact day of month, set the
+ * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
+ * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
+ * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
+ * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
+ * <em>day-of-month</em> to 8, and <em>day-of-week</em> to {@code -}{@link
+ * Calendar#SUNDAY SUNDAY}.</li>
+ *
+ * <li><b>Day of week on or before day of month</b><br>
+ * To specify a day of the week on or before an exact day of the month, set
+ * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
+ * example, to specify the last Wednesday on or before the 21st of March, set
+ * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
+ * and <em>day-of-week</em> is {@code -}{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
+ *
+ * <li><b>Last day-of-week of month</b><br>
+ * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
+ * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
+ * -1. For example, to specify the last Sunday of October, set <em>month</em>
+ * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
+ * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
+ *
+ * </ul>
+ * The time of the day at which daylight saving time starts or ends is
+ * specified by a millisecond value within the day. There are three kinds of
+ * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
+ * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
+ * saving time ends
+ * at 2:00 am in the wall clock time, it can be specified by 7200000
+ * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
+ * for an <em>end-rule</em> means the same thing as the daylight time.
+ * <p>
+ * The following are examples of parameters for constructing time zone objects.
+ * <pre><code>
+ *      // Base GMT offset: -8:00
+ *      // DST starts:      at 2:00am in standard time
+ *      //                  on the first Sunday in April
+ *      // DST ends:        at 2:00am in daylight time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(-28800000,
+ *                     "America/Los_Angeles",
+ *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
+ *                     7200000,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     7200000,
+ *                     3600000)
+ *
+ *      // Base GMT offset: +1:00
+ *      // DST starts:      at 1:00am in UTC time
+ *      //                  on the last Sunday in March
+ *      // DST ends:        at 1:00am in UTC time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(3600000,
+ *                     "Europe/Paris",
+ *                     Calendar.MARCH, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     3600000)
+ * </code></pre>
+ * These parameter rules are also applicable to the set rule methods, such as
+ * {@code setStartRule}.
+ *
+ * @since 1.1
+ * @see      Calendar
+ * @see      GregorianCalendar
+ * @see      TimeZone
+ * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+
+public class SimpleTimeZone extends TimeZone {
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
+     * and time zone ID with no daylight saving time schedule.
+     *
+     * @param rawOffset  The base time zone offset in milliseconds to GMT.
+     * @param ID         The time zone name that is given to this instance.
+     */
+    public SimpleTimeZone(int rawOffset, String ID)
+    {
+        this.rawOffset = rawOffset;
+        setID (ID);
+        dstSavings = millisPerHour; // In case user sets rules later
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both {@code startTime} and {@code endTime} are specified to be
+     * represented in the wall clock time. The amount of daylight saving is
+     * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
+     * equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    3600000)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
+     *                        for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time (in milliseconds within the day), which is local
+     *                        standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @throws    IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             millisPerHour);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both {@code startTime} and {@code endTime} are assumed to be
+     * represented in the wall clock time. This constructor is equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    dstSavings)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        which is local daylight time in this case.
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     * @throws    IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     * @since 1.2
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime,
+                          int dstSavings)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             dstSavings);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * This constructor takes the full set of the start and end rules
+     * parameters, including modes of {@code startTime} and
+     * {@code endTime}. The mode specifies either {@link #WALL_TIME wall
+     * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
+     * time}.
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in the time mode
+     *                        specified by {@code startTimeMode}.
+     * @param startTimeMode   The mode of the start time specified by startTime.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in time mode
+     *                        specified by {@code endTimeMode}.
+     * @param endTimeMode     The mode of the end time specified by endTime
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     *
+     * @throws    IllegalArgumentException if the month, day, dayOfWeek, time more, or
+     * time parameters are out of range for the start or end rule, or if a time mode
+     * value is invalid.
+     *
+     * @see #WALL_TIME
+     * @see #STANDARD_TIME
+     * @see #UTC_TIME
+     *
+     * @since 1.4
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek,
+                          int startTime, int startTimeMode,
+                          int endMonth, int endDay, int endDayOfWeek,
+                          int endTime, int endTimeMode,
+                          int dstSavings) {
+
+        setID(ID);
+        this.rawOffset      = rawOffset;
+        this.startMonth     = startMonth;
+        this.startDay       = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime      = startTime;
+        this.startTimeMode  = startTimeMode;
+        this.endMonth       = endMonth;
+        this.endDay         = endDay;
+        this.endDayOfWeek   = endDayOfWeek;
+        this.endTime        = endTime;
+        this.endTimeMode    = endTimeMode;
+        this.dstSavings     = dstSavings;
+
+        // this.useDaylight is set by decodeRules
+        decodeRules();
+        if (dstSavings <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time starting year.
+     *
+     * @param year  The daylight saving starting year.
+     */
+    public void setStartYear(int year)
+    {
+        startYear = year;
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule. For example, if daylight saving
+     * time starts on the first Sunday in April at 2 am in local wall clock
+     * time, you can set the start rule by calling:
+     * <pre>{@code setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);}</pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @throws    IllegalArgumentException if the {@code startMonth}, {@code startDay},
+     * {@code startDayOfWeek}, or {@code startTime} parameters are out of range
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
+    {
+        this.startMonth = startMonth;
+        this.startDay = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime = startTime;
+        startTimeMode = WALL_TIME;
+        decodeStartRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre>{@code setStartRule(startMonth, startDay, 0, startTime)}</pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     *                        See the class description for the special cases of this parameter.
+     * @throws    IllegalArgumentException if the {@code startMonth},
+     * {@code startDayOfMonth}, or {@code startTime} parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startTime) {
+        setStartRule(startMonth, startDay, 0, startTime);
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param after           If true, this rule selects the first {@code dayOfWeek} on or
+     *                        <em>after</em> {@code dayOfMonth}.  If false, this rule
+     *                        selects the last {@code dayOfWeek} on or <em>before</em>
+     *                        {@code dayOfMonth}.
+     * @throws    IllegalArgumentException if the {@code startMonth}, {@code startDay},
+     * {@code startDayOfWeek}, or {@code startTime} parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
+                             int startTime, boolean after)
+    {
+        // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
+        if (after) {
+            setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
+        } else {
+            setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time end rule. For example, if daylight saving time
+     * ends on the last Sunday in October at 2 am in wall clock time,
+     * you can set the end rule by calling:
+     * {@code setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);}
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @throws    IllegalArgumentException if the {@code endMonth}, {@code endDay},
+     * {@code endDayOfWeek}, or {@code endTime} parameters are out of range
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
+                           int endTime)
+    {
+        this.endMonth = endMonth;
+        this.endDay = endDay;
+        this.endDayOfWeek = endDayOfWeek;
+        this.endTime = endTime;
+        this.endTimeMode = WALL_TIME;
+        decodeEndRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre>{@code setEndRule(endMonth, endDay, 0, endTime)}</pre>
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @throws    IllegalArgumentException the {@code endMonth}, {@code endDay},
+     * or {@code endTime} parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endTime)
+    {
+        setEndRule(endMonth, endDay, 0, endTime);
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @param after           If true, this rule selects the first {@code endDayOfWeek} on
+     *                        or <em>after</em> {@code endDay}.  If false, this rule
+     *                        selects the last {@code endDayOfWeek} on or before
+     *                        {@code endDay} of the month.
+     * @throws    IllegalArgumentException the {@code endMonth}, {@code endDay},
+     * {@code endDayOfWeek}, or {@code endTime} parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
+    {
+        if (after) {
+            setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
+        } else {
+            setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
+        }
+    }
+
+    /**
+     * Returns the offset of this time zone from UTC at the given
+     * time. If daylight saving time is in effect at the given time,
+     * the offset value is adjusted with the amount of daylight
+     * saving.
+     *
+     * @param date the time at which the time zone offset is found
+     * @return the amount of time in milliseconds to add to UTC to get
+     * local time.
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        return getOffsets(date, null);
+    }
+
+    /**
+     * @see TimeZone#getOffsets
+     */
+    int getOffsets(long date, int[] offsets) {
+        int offset = rawOffset;
+
+      computeOffset:
+        if (useDaylight) {
+            Cache cache = this.cache;
+            if (cache != null) {
+                if (date >= cache.start && date < cache.end) {
+                    offset += dstSavings;
+                    break computeOffset;
+                }
+            }
+            BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
+                gcal : (BaseCalendar) CalendarSystem.forName("julian");
+            BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            // Get the year in local time
+            cal.getCalendarDate(date + rawOffset, cdate);
+            int year = cdate.getNormalizedYear();
+            if (year >= startYear) {
+                // Clear time elements for the transition calculations
+                cdate.setTimeOfDay(0, 0, 0, 0);
+                offset = getOffset(cal, cdate, year, date);
+            }
+        }
+
+        if (offsets != null) {
+            offsets[0] = rawOffset;
+            offsets[1] = offset - rawOffset;
+        }
+        return offset;
+    }
+
+    /**
+     * Returns the difference in milliseconds between local time and
+     * UTC, taking into account both the raw offset and the effect of
+     * daylight saving, for the specified date and time.  This method
+     * assumes that the start and end month are distinct.  It also
+     * uses a default {@link GregorianCalendar} object as its
+     * underlying calendar, such as for determining leap years.  Do
+     * not use the result of this method with a calendar other than a
+     * default {@code GregorianCalendar}.
+     *
+     * <p><em>Note:  In general, clients should use
+     * {@code Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)}
+     * instead of calling this method.</em>
+     *
+     * @param era       The era of the given date.
+     * @param year      The year in the given date.
+     * @param month     The month in the given date. Month is 0-based. e.g.,
+     *                  0 for January.
+     * @param day       The day-in-month of the given date.
+     * @param dayOfWeek The day-of-week of the given date.
+     * @param millis    The milliseconds in day in <em>standard</em> local time.
+     * @return          The milliseconds to add to UTC to get local time.
+     * @throws          IllegalArgumentException the {@code era},
+     *                  {@code month}, {@code day}, {@code dayOfWeek},
+     *                  or {@code millis} parameters are out of range
+     */
+    public int getOffset(int era, int year, int month, int day, int dayOfWeek,
+                         int millis)
+    {
+        if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
+            throw new IllegalArgumentException("Illegal era " + era);
+        }
+
+        int y = year;
+        if (era == GregorianCalendar.BC) {
+            // adjust y with the GregorianCalendar-style year numbering.
+            y = 1 - y;
+        }
+
+        // If the year isn't representable with the 64-bit long
+        // integer in milliseconds, convert the year to an
+        // equivalent year. This is required to pass some JCK test cases
+        // which are actually useless though because the specified years
+        // can't be supported by the Java time system.
+        if (y >= 292278994) {
+            y = 2800 + y % 2800;
+        } else if (y <= -292269054) {
+            // y %= 28 also produces an equivalent year, but positive
+            // year numbers would be convenient to use the UNIX cal
+            // command.
+            y = (int) CalendarUtils.mod((long) y, 28);
+        }
+
+        // convert year to its 1-based month value
+        int m = month + 1;
+
+        // First, calculate time as a Gregorian date.
+        BaseCalendar cal = gcal;
+        BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cdate.setDate(y, m, day);
+        long time = cal.getTime(cdate); // normalize cdate
+        time += millis - rawOffset; // UTC time
+
+        // If the time value represents a time before the default
+        // Gregorian cutover, recalculate time using the Julian
+        // calendar system. For the Julian calendar system, the
+        // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
+        // 1, 2 ... which is different from the GregorianCalendar
+        // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
+        if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
+            cal = (BaseCalendar) CalendarSystem.forName("julian");
+            cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            cdate.setNormalizedDate(y, m, day);
+            time = cal.getTime(cdate) + millis - rawOffset;
+        }
+
+        if ((cdate.getNormalizedYear() != y)
+            || (cdate.getMonth() != m)
+            || (cdate.getDayOfMonth() != day)
+            // The validation should be cdate.getDayOfWeek() ==
+            // dayOfWeek. However, we don't check dayOfWeek for
+            // compatibility.
+            || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
+            || (millis < 0 || millis >= (24*60*60*1000))) {
+            throw new IllegalArgumentException();
+        }
+
+        if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
+            return rawOffset;
+        }
+
+        return getOffset(cal, cdate, y, time);
+    }
+
+    private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
+        Cache cache = this.cache;
+        if (cache != null) {
+            if (time >= cache.start && time < cache.end) {
+                return rawOffset + dstSavings;
+            }
+            if (year == cache.year) {
+                return rawOffset;
+            }
+        }
+
+        long start = getStart(cal, cdate, year);
+        long end = getEnd(cal, cdate, year);
+        int offset = rawOffset;
+        if (start <= end) {
+            if (time >= start && time < end) {
+                offset += dstSavings;
+            }
+            this.cache = new Cache(year, start, end);
+        } else {
+            if (time < end) {
+                // TODO: support Gregorian cutover. The previous year
+                // may be in the other calendar system.
+                start = getStart(cal, cdate, year - 1);
+                if (time >= start) {
+                    offset += dstSavings;
+                }
+            } else if (time >= start) {
+                // TODO: support Gregorian cutover. The next year
+                // may be in the other calendar system.
+                end = getEnd(cal, cdate, year + 1);
+                if (time < end) {
+                    offset += dstSavings;
+                }
+            }
+            if (start <= end) {
+                this.cache = new Cache((long) startYear - 1, start, end);
+            }
+        }
+        return offset;
+    }
+
+    private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = startTime;
+        if (startTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        return getTransition(cal, cdate, startMode, year, startMonth, startDay,
+                             startDayOfWeek, time);
+    }
+
+    private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = endTime;
+        if (endTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        if (endTimeMode == WALL_TIME) {
+            time -= dstSavings;
+        }
+        return getTransition(cal, cdate, endMode, year, endMonth, endDay,
+                                        endDayOfWeek, time);
+    }
+
+    private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
+                               int mode, int year, int month, int dayOfMonth,
+                               int dayOfWeek, int timeOfDay) {
+        cdate.setNormalizedYear(year);
+        cdate.setMonth(month + 1);
+        switch (mode) {
+            case DOM_MODE -> cdate.setDayOfMonth(dayOfMonth);
+            case DOW_IN_MONTH_MODE -> {
+                cdate.setDayOfMonth(1);
+                if (dayOfMonth < 0) {
+                    cdate.setDayOfMonth(cal.getMonthLength(cdate));
+                }
+                cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
+            }
+            case DOW_GE_DOM_MODE -> {
+                cdate.setDayOfMonth(dayOfMonth);
+                cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
+            }
+            case DOW_LE_DOM_MODE -> {
+                cdate.setDayOfMonth(dayOfMonth);
+                cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
+            }
+        }
+        return cal.getTime(cdate) + timeOfDay;
+    }
+
+    /**
+     * Gets the GMT offset for this time zone.
+     * @return the GMT offset value in milliseconds
+     * @see #setRawOffset
+     */
+    public int getRawOffset()
+    {
+        // The given date will be taken into account while
+        // we have the historical time zone data in place.
+        return rawOffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * @see #getRawOffset
+     */
+    public void setRawOffset(int offsetMillis)
+    {
+        this.rawOffset = offsetMillis;
+    }
+
+    /**
+     * Sets the amount of time in milliseconds that the clock is advanced
+     * during daylight saving time.
+     * @param millisSavedDuringDST the number of milliseconds the time is
+     * advanced with respect to standard time when the daylight saving time rules
+     * are in effect. A positive number, typically one hour (3600000).
+     * @see #getDSTSavings
+     * @since 1.2
+     */
+    public void setDSTSavings(int millisSavedDuringDST) {
+        if (millisSavedDuringDST <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: "
+                                               + millisSavedDuringDST);
+        }
+        dstSavings = millisSavedDuringDST;
+    }
+
+    /**
+     * Returns the amount of time in milliseconds that the clock is
+     * advanced during daylight saving time.
+     *
+     * @return the number of milliseconds the time is advanced with
+     * respect to standard time when the daylight saving rules are in
+     * effect, or 0 (zero) if this time zone doesn't observe daylight
+     * saving time.
+     *
+     * @see #setDSTSavings
+     * @since 1.2
+     */
+    public int getDSTSavings() {
+        return useDaylight ? dstSavings : 0;
+    }
+
+    /**
+     * Queries if this time zone uses daylight saving time.
+     * @return true if this time zone uses daylight saving time;
+     * false otherwise.
+     */
+    public boolean useDaylightTime()
+    {
+        return useDaylight;
+    }
+
+    /**
+     * Returns {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time. This method is equivalent to {@link
+     * #useDaylightTime()}.
+     *
+     * @return {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time; {@code false} otherwise.
+     * @since 1.7
+     */
+    @Override
+    public boolean observesDaylightTime() {
+        return useDaylightTime();
+    }
+
+    /**
+     * Queries if the given date is in daylight saving time.
+     * @return true if daylight saving time is in effective at the
+     * given date; false otherwise.
+     */
+    public boolean inDaylightTime(Date date)
+    {
+        return (getOffset(date.getTime()) != rawOffset);
+    }
+
+    /**
+     * Returns a clone of this {@code SimpleTimeZone} instance.
+     * @return a clone of this instance.
+     */
+    public Object clone()
+    {
+        return super.clone();
+    }
+
+    /**
+     * Generates the hash code for the SimpleDateFormat object.
+     * @return the hash code for this object
+     */
+    public int hashCode()
+    {
+        return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
+            endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
+    }
+
+    /**
+     * Compares the equality of two {@code SimpleTimeZone} objects.
+     *
+     * @param obj  The {@code SimpleTimeZone} object to be compared with.
+     * @return     True if the given {@code obj} is the same as this
+     *             {@code SimpleTimeZone} object; false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        return obj instanceof SimpleTimeZone that
+                && getID().equals(that.getID())
+                && hasSameRules(that);
+    }
+
+    /**
+     * Returns {@code true} if this zone has the same rules and offset as another zone.
+     * @param other the TimeZone object to be compared with
+     * @return {@code true} if the given zone is a SimpleTimeZone and has the
+     * same rules and offset as this one
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        if (this == other) {
+            return true;
+        }
+        return other instanceof SimpleTimeZone that
+                && rawOffset == that.rawOffset
+                && useDaylight == that.useDaylight
+                && (!useDaylight ||
+                        // Only check rules if using DST
+                        (dstSavings == that.dstSavings
+                        && startMode == that.startMode
+                        && startMonth == that.startMonth
+                        && startDay == that.startDay
+                        && startDayOfWeek == that.startDayOfWeek
+                        && startTime == that.startTime
+                        && startTimeMode == that.startTimeMode
+                        && endMode == that.endMode
+                        && endMonth == that.endMonth
+                        && endDay == that.endDay
+                        && endDayOfWeek == that.endDayOfWeek
+                        && endTime == that.endTime
+                        && endTimeMode == that.endTimeMode
+                        && startYear == that.startYear)
+                    );
+    }
+
+    /**
+     * Returns a string representation of this time zone.
+     * @return a string representation of this time zone.
+     */
+    public String toString() {
+        return getClass().getName() +
+            "[id=" + getID() +
+            ",offset=" + rawOffset +
+            ",dstSavings=" + dstSavings +
+            ",useDaylight=" + useDaylight +
+            ",startYear=" + startYear +
+            ",startMode=" + startMode +
+            ",startMonth=" + startMonth +
+            ",startDay=" + startDay +
+            ",startDayOfWeek=" + startDayOfWeek +
+            ",startTime=" + startTime +
+            ",startTimeMode=" + startTimeMode +
+            ",endMode=" + endMode +
+            ",endMonth=" + endMonth +
+            ",endDay=" + endDay +
+            ",endDayOfWeek=" + endDayOfWeek +
+            ",endTime=" + endTime +
+            ",endTimeMode=" + endTimeMode + ']';
+    }
+
+    // =======================privates===============================
+
+    /**
+     * The month in which daylight saving time starts.  This value must be
+     * between {@code Calendar.JANUARY} and
+     * {@code Calendar.DECEMBER} inclusive.  This value must not equal
+     * {@code endMonth}.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int startMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt>{@code startMode == DOW_IN_MONTH}</dt>
+     * <dd>
+     * {@code startDay} indicates the day of the month of
+     * {@code startMonth} on which daylight
+     * saving time starts, from 1 to 28, 30, or 31, depending on the
+     * {@code startMonth}.
+     * </dd>
+     * <dt>{@code startMode != DOW_IN_MONTH}</dt>
+     * <dd>
+     * {@code startDay} indicates which {@code startDayOfWeek} in the
+     * month {@code startMonth} daylight
+     * saving time starts on.  For example, a value of +1 and a
+     * {@code startDayOfWeek} of {@code Calendar.SUNDAY} indicates the
+     * first Sunday of {@code startMonth}.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int startDay;
+
+    /**
+     * The day of the week on which daylight saving time starts.  This value
+     * must be between {@code Calendar.SUNDAY} and
+     * {@code Calendar.SATURDAY} inclusive.
+     * <p>If {@code useDaylight} is false or
+     * {@code startMode == DAY_OF_MONTH}, this value is ignored.
+     * @serial
+     */
+    private int startDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time starts.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of {@code startTimeMode}.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int startTime;
+
+    /**
+     * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
+     * @serial
+     * @since 1.3
+     */
+    private int startTimeMode;
+
+    /**
+     * The month in which daylight saving time ends.  This value must be
+     * between {@code Calendar.JANUARY} and
+     * {@code Calendar.UNDECIMBER}.  This value must not equal
+     * {@code startMonth}.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int endMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt>{@code endMode == DOW_IN_MONTH}</dt>
+     * <dd>
+     * {@code endDay} indicates the day of the month of
+     * {@code endMonth} on which daylight
+     * saving time ends, from 1 to 28, 30, or 31, depending on the
+     * {@code endMonth}.
+     * </dd>
+     * <dt>{@code endMode != DOW_IN_MONTH}</dt>
+     * <dd>
+     * {@code endDay} indicates which {@code endDayOfWeek} in th
+     * month {@code endMonth} daylight
+     * saving time ends on.  For example, a value of +1 and a
+     * {@code endDayOfWeek} of {@code Calendar.SUNDAY} indicates the
+     * first Sunday of {@code endMonth}.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int endDay;
+
+    /**
+     * The day of the week on which daylight saving time ends.  This value
+     * must be between {@code Calendar.SUNDAY} and
+     * {@code Calendar.SATURDAY} inclusive.
+     * <p>If {@code useDaylight} is false or
+     * {@code endMode == DAY_OF_MONTH}, this value is ignored.
+     * @serial
+     */
+    private int endDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time ends.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of {@code endTimeMode}.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int endTime;
+
+    /**
+     * The format of endTime, either {@code WALL_TIME},
+     * {@code STANDARD_TIME}, or {@code UTC_TIME}.
+     * @serial
+     * @since 1.3
+     */
+    private int endTimeMode;
+
+    /**
+     * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
+     * value.  If this value is less than 1 then daylight saving time is observed
+     * for all {@code AD} years.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     */
+    private int startYear;
+
+    /**
+     * The offset in milliseconds between this zone and GMT.  Negative offsets
+     * are to the west of Greenwich.  To obtain local <em>standard</em> time,
+     * add the offset to GMT time.  To obtain local wall time it may also be
+     * necessary to add {@code dstSavings}.
+     * @serial
+     */
+    private int rawOffset;
+
+    /**
+     * A boolean value which is true if and only if this zone uses daylight
+     * saving time.  If this value is false, several other fields are ignored.
+     * @serial
+     */
+    private boolean useDaylight=false; // indicate if this time zone uses DST
+
+    private static final int millisPerHour = 60*60*1000;
+    private static final int millisPerDay  = 24*millisPerHour;
+
+    /**
+     * This field was serialized in JDK 1.1, so we have to keep it that way
+     * to maintain serialization compatibility. However, there's no need to
+     * recreate the array each time we create a new time zone.
+     * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
+     * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
+     * be streamed out for compatibility with JDK 1.1.
+     */
+    private final byte monthLength[] = staticMonthLength;
+    private static final byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+    private static final byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
+
+    /**
+     * Variables specifying the mode of the start rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt>{@code DOM_MODE}</dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt>{@code DOW_IN_MONTH_MODE}</dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt>{@code DOW_GE_DOM_MODE}</dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt>{@code DOW_LE_DOM_MODE}</dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * {@code startDay} field.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int startMode;
+
+    /**
+     * Variables specifying the mode of the end rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt>{@code DOM_MODE}</dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt>{@code DOW_IN_MONTH_MODE}</dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt>{@code DOW_GE_DOM_MODE}</dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt>{@code DOW_LE_DOM_MODE}</dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * {@code endDay} field.
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int endMode;
+
+    /**
+     * A positive value indicating the amount of time saved during DST in
+     * milliseconds.
+     * Typically one hour (3600000); sometimes 30 minutes (1800000).
+     * <p>If {@code useDaylight} is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int dstSavings;
+
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    /**
+     * Cache values representing a single period of daylight saving
+     * time. Cache.start is the start time (inclusive) of daylight
+     * saving time and Cache.end is the end time (exclusive).
+     *
+     * Cache.year has a year value if both Cache.start and Cache.end are
+     * in the same year. Cache.year is set to startYear - 1 if
+     * Cache.start and Cache.end are in different years.
+     * Cache.year is a long to support Integer.MIN_VALUE - 1 (JCK requirement).
+     */
+    private static final class Cache {
+        final long year;
+        final long start;
+        final long end;
+
+        Cache(long year, long start, long end) {
+            this.year = year;
+            this.start = start;
+            this.end = end;
+        }
+    }
+
+    private transient volatile Cache cache;
+
+    /**
+     * Constants specifying values of startMode and endMode.
+     */
+    private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
+    private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
+    private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
+    private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
+
+    /**
+     * Constant for a mode of start or end time specified as wall clock
+     * time.  Wall clock time is standard time for the onset rule, and
+     * daylight time for the end rule.
+     * @since 1.4
+     */
+    public static final int WALL_TIME = 0; // Zero for backward compatibility
+
+    /**
+     * Constant for a mode of start or end time specified as standard time.
+     * @since 1.4
+     */
+    public static final int STANDARD_TIME = 1;
+
+    /**
+     * Constant for a mode of start or end time specified as UTC. European
+     * Union rules are specified as UTC time, for example.
+     * @since 1.4
+     */
+    public static final int UTC_TIME = 2;
+
+    // Proclaim compatibility with 1.1
+    @java.io.Serial
+    static final long serialVersionUID = -403250971215465050L;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.3
+    // - 1 for version from JDK 1.1.4, which includes 3 new fields
+    // - 2 for JDK 1.3, which includes 2 new fields
+    static final int currentSerialVersion = 2;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.3 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.4 or later.  Includes three new fields: {@code startMode},
+     * {@code endMode}, and {@code dstSavings}.
+     * </dd>
+     * <dt><b>2</b></dt>
+     * <dd>
+     * JDK 1.3 or later.  Includes two new fields: {@code startTimeMode}
+     * and {@code endTimeMode}.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable {@code serialVersionOnStream}
+     * is written.
+     * @serial
+     * @since 1.1.4
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    // Maximum number of rules.
+    private static final int MAX_RULE_NUM = 6;
+
+    private void invalidateCache() {
+        cache = null;
+    }
+
+    //----------------------------------------------------------------------
+    // Rule representation
+    //
+    // We represent the following flavors of rules:
+    //       5        the fifth of the month
+    //       lastSun  the last Sunday in the month
+    //       lastMon  the last Monday in the month
+    //       Sun>=8   first Sunday on or after the eighth
+    //       Sun<=25  last Sunday on or before the 25th
+    // This is further complicated by the fact that we need to remain
+    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
+    // API changes.  In order to satisfy these requirements, we support
+    // three representation systems, and we translate between them.
+    //
+    // INTERNAL REPRESENTATION
+    // This is the format SimpleTimeZone objects take after construction or
+    // streaming in is complete.  Rules are represented directly, using an
+    // unencoded format.  We will discuss the start rule only below; the end
+    // rule is analogous.
+    //   startMode      Takes on enumerated values DAY_OF_MONTH,
+    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
+    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
+    //                  value indicating which DOW, such as +1 for first,
+    //                  +2 for second, -1 for last, etc.
+    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
+    //
+    // ENCODED REPRESENTATION
+    // This is the format accepted by the constructor and by setStartRule()
+    // and setEndRule().  It uses various combinations of positive, negative,
+    // and zero values to encode the different rules.  This representation
+    // allows us to specify all the different rule flavors without altering
+    // the API.
+    //   MODE              startMonth    startDay    startDayOfWeek
+    //   DOW_IN_MONTH_MODE >=0           !=0         >0
+    //   DOM_MODE          >=0           >0          ==0
+    //   DOW_GE_DOM_MODE   >=0           >0          <0
+    //   DOW_LE_DOM_MODE   >=0           <0          <0
+    //   (no DST)          don't care    ==0         don't care
+    //
+    // STREAMED REPRESENTATION
+    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
+    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
+    // flag useDaylight.  When we stream an object out, we translate into an
+    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
+    // and used by 1.1 code.  Following that, we write out the full
+    // representation separately so that contemporary code can recognize and
+    // parse it.  The full representation is written in a "packed" format,
+    // consisting of a version number, a length, and an array of bytes.  Future
+    // versions of this class may specify different versions.  If they wish to
+    // include additional data, they should do so by storing them after the
+    // packed representation below.
+    //----------------------------------------------------------------------
+
+    /**
+     * Given a set of encoded rules in startDay and startDayOfMonth, decode
+     * them and set the startMode appropriately.  Do the same for endDay and
+     * endDayOfMonth.  Upon entry, the day of week variables may be zero or
+     * negative, in order to indicate special modes.  The day of month
+     * variables may also be negative.  Upon exit, the mode variables will be
+     * set, and the day of week and day of month variables will be positive.
+     * This method also recognizes a startDay or endDay of zero as indicating
+     * no DST.
+     */
+    private void decodeRules()
+    {
+        decodeStartRule();
+        decodeEndRule();
+    }
+
+    /**
+     * Decode the start rule and validate the parameters.  The parameters are
+     * expected to be in encoded form, which represents the various rule modes
+     * by negating or zeroing certain values.  Representation formats are:
+     * <p>
+     * <pre>
+     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
+     *            ------------  -----  --------  --------  ----------
+     * month       0..11        same    same      same     don't care
+     * day        -5..5         1..31   1..31    -1..-31   0
+     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
+     * time        0..ONEDAY    same    same      same     don't care
+     * </pre>
+     * The range for month does not include UNDECIMBER since this class is
+     * really specific to GregorianCalendar, which does not use that month.
+     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
+     * end rule is an exclusive limit point.  That is, the range of times that
+     * are in DST include those >= the start and < the end.  For this reason,
+     * it should be possible to specify an end of ONEDAY in order to include the
+     * entire day.  Although this is equivalent to time 0 of the following day,
+     * it's not always possible to specify that, for example, on December 31.
+     * While arguably the start range should still be 0..ONEDAY-1, we keep
+     * the start and end ranges the same for consistency.
+     */
+    private void decodeStartRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (startDay != 0) {
+            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal start month " + startMonth);
+            }
+            if (startTime < 0 || startTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal start time " + startTime);
+            }
+            if (startDayOfWeek == 0) {
+                startMode = DOM_MODE;
+            } else {
+                if (startDayOfWeek > 0) {
+                    startMode = DOW_IN_MONTH_MODE;
+                } else {
+                    startDayOfWeek = -startDayOfWeek;
+                    if (startDay > 0) {
+                        startMode = DOW_GE_DOM_MODE;
+                    } else {
+                        startDay = -startDay;
+                        startMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (startDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal start day of week " + startDayOfWeek);
+                }
+            }
+            if (startMode == DOW_IN_MONTH_MODE) {
+                if (startDay < -5 || startDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal start day of week in month " + startDay);
+                }
+            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal start day " + startDay);
+            }
+        }
+    }
+
+    /**
+     * Decode the end rule and validate the parameters.  This method is exactly
+     * analogous to decodeStartRule().
+     * @see decodeStartRule
+     */
+    private void decodeEndRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (endDay != 0) {
+            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal end month " + endMonth);
+            }
+            if (endTime < 0 || endTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal end time " + endTime);
+            }
+            if (endDayOfWeek == 0) {
+                endMode = DOM_MODE;
+            } else {
+                if (endDayOfWeek > 0) {
+                    endMode = DOW_IN_MONTH_MODE;
+                } else {
+                    endDayOfWeek = -endDayOfWeek;
+                    if (endDay > 0) {
+                        endMode = DOW_GE_DOM_MODE;
+                    } else {
+                        endDay = -endDay;
+                        endMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (endDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal end day of week " + endDayOfWeek);
+                }
+            }
+            if (endMode == DOW_IN_MONTH_MODE) {
+                if (endDay < -5 || endDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal end day of week in month " + endDay);
+                }
+            } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal end day " + endDay);
+            }
+        }
+    }
+
+    /**
+     * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
+     * day-of-week-in-month rules, we must modify other modes of rules to their
+     * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
+     * out objects of this class.  After it is called, the rules will be modified,
+     * with a possible loss of information.  startMode and endMode will NOT be
+     * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
+     * since the rule modification is only intended to be temporary.
+     */
+    private void makeRulesCompatible()
+    {
+        switch (startMode) {
+        case DOM_MODE:
+            startDay = 1 + (startDay / 7);
+            startDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (startDay != 1) {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (startDay >= 30) {
+                startDay = -1;
+            } else {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+        }
+
+        switch (endMode) {
+        case DOM_MODE:
+            endDay = 1 + (endDay / 7);
+            endDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (endDay != 1) {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (endDay >= 30) {
+                endDay = -1;
+            } else {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+        }
+
+        /*
+         * Adjust the start and end times to wall time.  This works perfectly
+         * well unless it pushes into the next or previous day.  If that
+         * happens, we attempt to adjust the day rule somewhat crudely.  The day
+         * rules have been forced into DOW_IN_MONTH mode already, so we change
+         * the day of week to move forward or back by a day.  It's possible to
+         * make a more refined adjustment of the original rules first, but in
+         * most cases this extra effort will go to waste once we adjust the day
+         * rules anyway.
+         */
+        switch (startTimeMode) {
+            case UTC_TIME -> startTime += rawOffset;
+        }
+        while (startTime < 0) {
+            startTime += millisPerDay;
+            startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (startTime >= millisPerDay) {
+            startTime -= millisPerDay;
+            startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
+        }
+
+        switch (endTimeMode) {
+            case UTC_TIME -> endTime += rawOffset + dstSavings;
+            case STANDARD_TIME -> endTime += dstSavings;
+        }
+        while (endTime < 0) {
+            endTime += millisPerDay;
+            endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (endTime >= millisPerDay) {
+            endTime -= millisPerDay;
+            endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
+        }
+    }
+
+    /**
+     * Pack the start and end rules into an array of bytes.  Only pack
+     * data which is not preserved by makeRulesCompatible.
+     */
+    private byte[] packRules()
+    {
+        byte[] rules = new byte[MAX_RULE_NUM];
+        rules[0] = (byte)startDay;
+        rules[1] = (byte)startDayOfWeek;
+        rules[2] = (byte)endDay;
+        rules[3] = (byte)endDayOfWeek;
+
+        // As of serial version 2, include time modes
+        rules[4] = (byte)startTimeMode;
+        rules[5] = (byte)endTimeMode;
+
+        return rules;
+    }
+
+    /**
+     * Given an array of bytes produced by packRules, interpret them
+     * as the start and end rules.
+     */
+    private void unpackRules(byte[] rules)
+    {
+        startDay       = rules[0];
+        startDayOfWeek = rules[1];
+        endDay         = rules[2];
+        endDayOfWeek   = rules[3];
+
+        // As of serial version 2, include time modes
+        if (rules.length >= MAX_RULE_NUM) {
+            startTimeMode = rules[4];
+            endTimeMode   = rules[5];
+        }
+    }
+
+    /**
+     * Pack the start and end times into an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private int[] packTimes() {
+        int[] times = new int[2];
+        times[0] = startTime;
+        times[1] = endTime;
+        return times;
+    }
+
+    /**
+     * Unpack the start and end times from an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private void unpackTimes(int[] times) {
+        startTime = times[0];
+        endTime = times[1];
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData We write out two formats, a JDK 1.1 compatible format, using
+     * {@code DOW_IN_MONTH_MODE} rules, in the required section, followed
+     * by the full rules, in packed format, in the optional section.  The
+     * optional section will be ignored by JDK 1.1 code upon stream in.
+     * <p> Contents of the optional section: The length of a byte array is
+     * emitted (int); this is 4 as of this release. The byte array of the given
+     * length is emitted. The contents of the byte array are the true values of
+     * the fields {@code startDay}, {@code startDayOfWeek},
+     * {@code endDay}, and {@code endDayOfWeek}.  The values of these
+     * fields in the required section are approximate values suited to the rule
+     * mode {@code DOW_IN_MONTH_MODE}, which is the only mode recognized by
+     * JDK 1.1.
+     */
+    @java.io.Serial
+    private void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Construct a binary rule
+        byte[] rules = packRules();
+        int[] times = packTimes();
+
+        // Convert to 1.1 FCS rules.  This step may cause us to lose information.
+        makeRulesCompatible();
+
+        // Write out the 1.1 FCS rules
+        stream.defaultWriteObject();
+
+        // Write out the binary rules in the optional data area of the stream.
+        stream.writeInt(rules.length);
+        stream.write(rules);
+        stream.writeObject(times);
+
+        // Recover the original rules.  This recovers the information lost
+        // by makeRulesCompatible.
+        unpackRules(rules);
+        unpackTimes(times);
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     *
+     * We handle both JDK 1.1
+     * binary formats and full formats with a packed byte array.
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+
+        if (serialVersionOnStream < 1) {
+            // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
+            // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
+            // too much, so we assume SUNDAY, which actually works most of the time.
+            if (startDayOfWeek == 0) {
+                startDayOfWeek = Calendar.SUNDAY;
+            }
+            if (endDayOfWeek == 0) {
+                endDayOfWeek = Calendar.SUNDAY;
+            }
+
+            // The variables dstSavings, startMode, and endMode are post-1.1, so they
+            // won't be present if we're reading from a 1.1 stream.  Fix them up.
+            startMode = endMode = DOW_IN_MONTH_MODE;
+            dstSavings = millisPerHour;
+        } else {
+            // For 1.1.4, in addition to the 3 new instance variables, we also
+            // store the actual rules (which have not be made compatible with 1.1)
+            // in the optional area.  Read them in here and parse them.
+            int length = stream.readInt();
+            if (length <= MAX_RULE_NUM) {
+                byte[] rules = new byte[length];
+                stream.readFully(rules);
+                unpackRules(rules);
+            } else {
+                throw new InvalidObjectException("Too many rules: " + length);
+            }
+        }
+
+        if (serialVersionOnStream >= 2) {
+            int[] times = (int[]) stream.readObject();
+            unpackTimes(times);
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+    }
+}
diff --git a/android-35/java/util/SortedMap.java b/android-35/java/util/SortedMap.java
new file mode 100644
index 0000000..4441bd7
--- /dev/null
+++ b/android-35/java/util/SortedMap.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Map} that further provides a <em>total ordering</em> on its keys.
+ * The map is ordered according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} typically
+ * provided at sorted map creation time.  This order is reflected when
+ * iterating over the sorted map's collection views (returned by the
+ * {@code entrySet}, {@code keySet} and {@code values} methods).
+ * Several additional operations are provided to take advantage of the
+ * ordering.  (This interface is the map analogue of {@link SortedSet}.)
+ *
+ * <p>All keys inserted into a sorted map must implement the {@code Comparable}
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such keys must be <em>mutually comparable</em>: {@code k1.compareTo(k2)} (or
+ * {@code comparator.compare(k1, k2)}) must not throw a
+ * {@code ClassCastException} for any keys {@code k1} and {@code k2} in
+ * the sorted map.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * {@code ClassCastException}.
+ *
+ * <p>Note that the ordering maintained by a sorted map (whether or not an
+ * explicit comparator is provided) must be <em>consistent with equals</em> if
+ * the sorted map is to correctly implement the {@code Map} interface.  (See
+ * the {@code Comparable} interface or {@code Comparator} interface for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its
+ * {@code compareTo} (or {@code compare}) method, so two keys that are
+ * deemed equal by this method are, from the standpoint of the sorted map,
+ * equal.  The behavior of a tree map <em>is</em> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the {@code Map} interface.
+ *
+ * <p>All general-purpose sorted map implementation classes should provide four
+ * "standard" constructors. It is not possible to enforce this recommendation
+ * though as required constructors cannot be specified by interfaces. The
+ * expected "standard" constructors for all sorted map implementations are:
+ * <ol>
+ *   <li>A void (no arguments) constructor, which creates an empty sorted map
+ *   sorted according to the natural ordering of its keys.</li>
+ *   <li>A constructor with a single argument of type {@code Comparator}, which
+ *   creates an empty sorted map sorted according to the specified comparator.</li>
+ *   <li>A constructor with a single argument of type {@code Map}, which creates
+ *   a new map with the same key-value mappings as its argument, sorted
+ *   according to the keys' natural ordering.</li>
+ *   <li>A constructor with a single argument of type {@code SortedMap}, which
+ *   creates a new sorted map with the same key-value mappings and the same
+ *   ordering as the input sorted map.</li>
+ * </ol>
+ *
+ * <p><strong>Note</strong>: several methods return submaps with restricted key
+ * ranges. Such ranges are <em>half-open</em>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).  If you need a
+ * <em>closed range</em> (which includes both endpoints), and the key type
+ * allows for calculation of the successor of a given key, merely request
+ * the subrange from {@code lowEndpoint} to
+ * {@code successor(highEndpoint)}.  For example, suppose that {@code m}
+ * is a map whose keys are strings.  The following idiom obtains a view
+ * containing all of the key-value mappings in {@code m} whose keys are
+ * between {@code low} and {@code high}, inclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <em>open range</em>
+ * (which contains neither endpoint).  The following idiom obtains a
+ * view containing all of the key-value mappings in {@code m} whose keys
+ * are between {@code low} and {@code high}, exclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see Map
+ * @see TreeMap
+ * @see SortedSet
+ * @see Comparator
+ * @see Comparable
+ * @see Collection
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedMap<K,V> extends SequencedMap<K,V>, Map<K,V> {
+    /**
+     * Returns the comparator used to order the keys in this map, or
+     * {@code null} if this map uses the {@linkplain Comparable
+     * natural ordering} of its keys.
+     *
+     * @return the comparator used to order the keys in this map,
+     *         or {@code null} if this map uses the natural ordering
+     *         of its keys
+     */
+    Comparator<? super K> comparator();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey}, inclusive, to {@code toKey}, exclusive.  (If
+     * {@code fromKey} and {@code toKey} are equal, the returned map
+     * is empty.)  The returned map is backed by this map, so changes
+     * in the returned map are reflected in this map, and vice-versa.
+     * The returned map supports all optional map operations that this
+     * map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey}, inclusive, to {@code toKey}, exclusive
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * strictly less than {@code toKey}.  The returned map is backed
+     * by this map, so changes in the returned map are reflected in
+     * this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are strictly
+     *         less than {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * greater than or equal to {@code fromKey}.  The returned map is
+     * backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map
+     * supports all optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are greater
+     *         than or equal to {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns the first (lowest) key currently in this map.
+     *
+     * @return the first (lowest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K firstKey();
+
+    /**
+     * Returns the last (highest) key currently in this map.
+     *
+     * @return the last (highest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K lastKey();
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map, sorted in
+     *         ascending order
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection's iterator returns the values in ascending order
+     * of the corresponding keys.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map,
+     *         sorted in ascending key order
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set's iterator returns the entries in ascending key order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    Set<Map.Entry<K, V>> entrySet();
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+     default V putFirst(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    default V putLast(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns a reverse-ordered SortedMap
+     * view. The {@code reversed()} method of the view returns a reference
+     * to this SortedMap. Other operations on the view are implemented via calls to
+     * public methods on this SortedMap. The exact relationship between calls on the
+     * view and calls on this SortedMap is unspecified. However, order-sensitive
+     * operations generally delegate to the appropriate method with the opposite
+     * orientation. For example, calling {@code firstEntry} on the view results in
+     * a call to {@code lastEntry} on this SortedMap.
+     *
+     * @return a reverse-ordered view of this map, as a {@code SortedMap}
+     * @since 21
+     */
+    default SortedMap<K, V> reversed() {
+        return ReverseOrderSortedMapView.of(this);
+    }
+}
diff --git a/android-35/java/util/SortedSet.java b/android-35/java/util/SortedSet.java
new file mode 100644
index 0000000..3b46124
--- /dev/null
+++ b/android-35/java/util/SortedSet.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Set} that further provides a <i>total ordering</i> on its elements.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} typically provided at sorted
+ * set creation time.  The set's iterator will traverse the set in
+ * ascending element order. Several additional operations are provided
+ * to take advantage of the ordering.  (This interface is the set
+ * analogue of {@link SortedMap}.)
+ *
+ * <p>All elements inserted into a sorted set must implement the {@code Comparable}
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such elements must be <i>mutually comparable</i>: {@code e1.compareTo(e2)}
+ * (or {@code comparator.compare(e1, e2)}) must not throw a
+ * {@code ClassCastException} for any elements {@code e1} and {@code e2} in
+ * the sorted set.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * {@code ClassCastException}.
+ *
+ * <p>Note that the ordering maintained by a sorted set (whether or not an
+ * explicit comparator is provided) must be <i>consistent with equals</i> if
+ * the sorted set is to correctly implement the {@code Set} interface.  (See
+ * the {@code Comparable} interface or {@code Comparator} interface for a
+ * precise definition of <i>consistent with equals</i>.)  This is so because
+ * the {@code Set} interface is defined in terms of the {@code equals}
+ * operation, but a sorted set performs all element comparisons using its
+ * {@code compareTo} (or {@code compare}) method, so two elements that are
+ * deemed equal by this method are, from the standpoint of the sorted set,
+ * equal.  The behavior of a sorted set <i>is</i> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the {@code Set} interface.
+ *
+ * <p>All general-purpose sorted set implementation classes should
+ * provide four "standard" constructors: 1) A void (no arguments)
+ * constructor, which creates an empty sorted set sorted according to
+ * the natural ordering of its elements.  2) A constructor with a
+ * single argument of type {@code Comparator}, which creates an empty
+ * sorted set sorted according to the specified comparator.  3) A
+ * constructor with a single argument of type {@code Collection},
+ * which creates a new sorted set with the same elements as its
+ * argument, sorted according to the natural ordering of the elements.
+ * 4) A constructor with a single argument of type {@code SortedSet},
+ * which creates a new sorted set with the same elements and the same
+ * ordering as the input sorted set.  There is no way to enforce this
+ * recommendation, as interfaces cannot contain constructors.
+ *
+ * <p>Note: several methods return subsets with restricted ranges.
+ * Such ranges are <i>half-open</i>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).
+ * If you need a <i>closed range</i> (which includes both endpoints), and
+ * the element type allows for calculation of the successor of a given
+ * value, merely request the subrange from {@code lowEndpoint} to
+ * {@code successor(highEndpoint)}.  For example, suppose that {@code s}
+ * is a sorted set of strings.  The following idiom obtains a view
+ * containing all of the strings in {@code s} from {@code low} to
+ * {@code high}, inclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <i>open range</i> (which
+ * contains neither endpoint).  The following idiom obtains a view
+ * containing all of the Strings in {@code s} from {@code low} to
+ * {@code high}, exclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see Set
+ * @see TreeSet
+ * @see SortedMap
+ * @see Collection
+ * @see Comparable
+ * @see Comparator
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedSet<E> extends Set<E>, SequencedSet<E> {
+    /**
+     * Returns the comparator used to order the elements in this set,
+     * or {@code null} if this set uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this set,
+     *         or {@code null} if this set uses the natural ordering
+     *         of its elements
+     */
+    Comparator<? super E> comparator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range
+     * from {@code fromElement}, inclusive, to {@code toElement},
+     * exclusive.  (If {@code fromElement} and {@code toElement} are
+     * equal, the returned set is empty.)  The returned set is backed
+     * by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements range from
+     *         {@code fromElement}, inclusive, to {@code toElement}, exclusive
+     * @throws ClassCastException if {@code fromElement} and
+     *         {@code toElement} cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if {@code fromElement} or
+     *         {@code toElement} cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set does not permit null
+     *         elements
+     * @throws IllegalArgumentException if {@code fromElement} is
+     *         greater than {@code toElement}; or if this set itself
+     *         has a restricted range, and {@code fromElement} or
+     *         {@code toElement} lies outside the bounds of the range
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * strictly less than {@code toElement}.  The returned set is
+     * backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements are strictly
+     *         less than {@code toElement}
+     * @throws ClassCastException if {@code toElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code toElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code toElement} lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * greater than or equal to {@code fromElement}.  The returned
+     * set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to {@code fromElement}
+     * @throws ClassCastException if {@code fromElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code fromElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code fromElement} lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> tailSet(E fromElement);
+
+    /**
+     * Returns the first (lowest) element currently in this set.
+     *
+     * @return the first (lowest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E first();
+
+    /**
+     * Returns the last (highest) element currently in this set.
+     *
+     * @return the last (highest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E last();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this sorted set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) must be {@code null} if
+     * the sorted set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator must be the same as or impose the
+     * same total ordering as the sorted set's comparator.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the sorted set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.  The
+     * spliterator's comparator is the same as the sorted set's comparator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this sorted set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return new Spliterators.IteratorSpliterator<E>(
+                this, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) {
+            @Override
+            public Comparator<? super E> getComparator() {
+                return SortedSet.this.comparator();
+            }
+        };
+    }
+
+    // ========== SequencedCollection ==========
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    default void addFirst(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @implSpec
+     * The implementation in this interface always throws {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    default void addLast(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns the result of calling the {@code first} method.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    default E getFirst() {
+        return this.first();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns the result of calling the {@code last} method.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    default E getLast() {
+        return this.last();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface calls the {@code first} method to obtain the first
+     * element, then it calls {@code remove(element)} to remove the element, and then it returns
+     * the element.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeFirst() {
+        E e = this.first();
+        this.remove(e);
+        return e;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface calls the {@code last} method to obtain the last
+     * element, then it calls {@code remove(element)} to remove the element, and then it returns
+     * the element.
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @since 21
+     */
+    default E removeLast() {
+        E e = this.last();
+        this.remove(e);
+        return e;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The implementation in this interface returns a reverse-ordered SortedSet
+     * view. The {@code reversed()} method of the view returns a reference
+     * to this SortedSet. Other operations on the view are implemented via calls to
+     * public methods on this SortedSet. The exact relationship between calls on the
+     * view and calls on this SortedSet is unspecified. However, order-sensitive
+     * operations generally delegate to the appropriate method with the opposite
+     * orientation. For example, calling {@code getFirst} on the view results in
+     * a call to {@code getLast} on this SortedSet.
+     *
+     * @return a reverse-ordered view of this collection, as a {@code SortedSet}
+     * @since 21
+     */
+    default SortedSet<E> reversed() {
+        return ReverseOrderSortedSetView.of(this);
+    }
+}
diff --git a/android-35/java/util/Spliterator.java b/android-35/java/util/Spliterator.java
new file mode 100644
index 0000000..0f49a18
--- /dev/null
+++ b/android-35/java/util/Spliterator.java
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An object for traversing and partitioning elements of a source.  The source
+ * of elements covered by a Spliterator could be, for example, an array, a
+ * {@link Collection}, an IO channel, or a generator function.
+ *
+ * <p>A Spliterator may traverse elements individually ({@link
+ * #tryAdvance tryAdvance()}) or sequentially in bulk
+ * ({@link #forEachRemaining forEachRemaining()}).
+ *
+ * <p>A Spliterator may also partition off some of its elements (using
+ * {@link #trySplit}) as another Spliterator, to be used in
+ * possibly-parallel operations.  Operations using a Spliterator that
+ * cannot split, or does so in a highly imbalanced or inefficient
+ * manner, are unlikely to benefit from parallelism.  Traversal
+ * and splitting exhaust elements; each Spliterator is useful for only a single
+ * bulk computation.
+ *
+ * <p>A Spliterator also reports a set of {@link #characteristics()} of its
+ * structure, source, and elements from among {@link #ORDERED},
+ * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL},
+ * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may
+ * be employed by Spliterator clients to control, specialize or simplify
+ * computation.  For example, a Spliterator for a {@link Collection} would
+ * report {@code SIZED}, a Spliterator for a {@link Set} would report
+ * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also
+ * report {@code SORTED}.  Characteristics are reported as a simple unioned bit
+ * set.
+ *
+ * Some characteristics additionally constrain method behavior; for example if
+ * {@code ORDERED}, traversal methods must conform to their documented ordering.
+ * New characteristics may be defined in the future, so implementors should not
+ * assign meanings to unlisted values.
+ *
+ * <p><a id="binding">A Spliterator that does not report {@code IMMUTABLE} or
+ * {@code CONCURRENT} is expected to have a documented policy concerning:
+ * when the spliterator <em>binds</em> to the element source; and detection of
+ * structural interference of the element source detected after binding.</a>  A
+ * <em>late-binding</em> Spliterator binds to the source of elements at the
+ * point of first traversal, first split, or first query for estimated size,
+ * rather than at the time the Spliterator is created.  A Spliterator that is
+ * not <em>late-binding</em> binds to the source of elements at the point of
+ * construction or first invocation of any method.  Modifications made to the
+ * source prior to binding are reflected when the Spliterator is traversed.
+ * After binding a Spliterator should, on a best-effort basis, throw
+ * {@link ConcurrentModificationException} if structural interference is
+ * detected.  Spliterators that do this are called <em>fail-fast</em>.  The
+ * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a
+ * Spliterator may optimize traversal and check for structural interference
+ * after all elements have been traversed, rather than checking per-element and
+ * failing immediately.
+ *
+ * <p>Spliterators can provide an estimate of the number of remaining elements
+ * via the {@link #estimateSize} method.  Ideally, as reflected in characteristic
+ * {@link #SIZED}, this value corresponds exactly to the number of elements
+ * that would be encountered in a successful traversal.  However, even when not
+ * exactly known, an estimated value may still be useful to operations
+ * being performed on the source, such as helping to determine whether it is
+ * preferable to split further or traverse the remaining elements sequentially.
+ *
+ * <p>Despite their obvious utility in parallel algorithms, spliterators are not
+ * expected to be thread-safe; instead, implementations of parallel algorithms
+ * using spliterators should ensure that the spliterator is only used by one
+ * thread at a time.  This is generally easy to attain via <em>serial
+ * thread-confinement</em>, which often is a natural consequence of typical
+ * parallel algorithms that work by recursive decomposition.  A thread calling
+ * {@link #trySplit()} may hand over the returned Spliterator to another thread,
+ * which in turn may traverse or further split that Spliterator.  The behaviour
+ * of splitting and traversal is undefined if two or more threads operate
+ * concurrently on the same spliterator.  If the original thread hands a
+ * spliterator off to another thread for processing, it is best if that handoff
+ * occurs before any elements are consumed with {@link #tryAdvance(Consumer)
+ * tryAdvance()}, as certain guarantees (such as the accuracy of
+ * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before
+ * traversal has begun.
+ *
+ * <p>Primitive subtype specializations of {@code Spliterator} are provided for
+ * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values.
+ * The subtype default implementations of
+ * {@link Spliterator#tryAdvance(java.util.function.Consumer)}
+ * and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may undermine any performance advantages gained by using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example,
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)}
+ * and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and
+ * {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ * Traversal of primitive values using boxing-based methods
+ * {@link #tryAdvance tryAdvance()} and
+ * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()}
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @apiNote
+ * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of
+ * a source.  The {@code Spliterator} API was designed to support efficient
+ * parallel traversal in addition to sequential traversal, by supporting
+ * decomposition as well as single-element iteration.  In addition, the
+ * protocol for accessing elements via a Spliterator is designed to impose
+ * smaller per-element overhead than {@code Iterator}, and to avoid the inherent
+ * race involved in having separate methods for {@code hasNext()} and
+ * {@code next()}.
+ *
+ * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if
+ * the source is structurally interfered with (elements added, replaced, or
+ * removed) between the time that the Spliterator binds to its data source and
+ * the end of traversal.  For example, such interference will produce arbitrary,
+ * non-deterministic results when using the {@code java.util.stream} framework.
+ *
+ * <p>Structural interference of a source can be managed in the following ways
+ * (in approximate order of decreasing desirability):
+ * <ul>
+ * <li>The source cannot be structurally interfered with.
+ * <br>For example, an instance of
+ * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
+ * A Spliterator created from the source reports a characteristic of
+ * {@code IMMUTABLE}.</li>
+ * <li>The source manages concurrent modifications.
+ * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
+ * is a concurrent source.  A Spliterator created from the source reports a
+ * characteristic of {@code CONCURRENT}.</li>
+ * <li>The mutable source provides a late-binding and fail-fast Spliterator.
+ * <br>Late binding narrows the window during which interference can affect
+ * the calculation; fail-fast detects, on a best-effort basis, that structural
+ * interference has occurred after traversal has commenced and throws
+ * {@link ConcurrentModificationException}.  For example, {@link ArrayList},
+ * and many other non-concurrent {@code Collection} classes in the JDK, provide
+ * a late-binding, fail-fast spliterator.</li>
+ * <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
+ * <br>The source increases the likelihood of throwing
+ * {@code ConcurrentModificationException} since the window of potential
+ * interference is larger.</li>
+ * <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
+ * <br>The source risks arbitrary, non-deterministic behavior after traversal
+ * has commenced since interference is not detected.
+ * </li>
+ * <li>The mutable source provides a non-late-binding and non-fail-fast
+ * Spliterator.
+ * <br>The source increases the risk of arbitrary, non-deterministic behavior
+ * since non-detected interference may occur after construction.
+ * </li>
+ * </ul>
+ *
+ * <p><b>Example.</b> Here is a class (not a very useful one, except
+ * for illustration) that maintains an array in which the actual data
+ * are held in even locations, and unrelated tag data are held in odd
+ * locations. Its Spliterator ignores the tags.
+ *
+ * <pre> {@code
+ * class TaggedArray<T> {
+ *   private final Object[] elements; // immutable after construction
+ *   TaggedArray(T[] data, Object[] tags) {
+ *     int size = data.length;
+ *     if (tags.length != size) throw new IllegalArgumentException();
+ *     this.elements = new Object[2 * size];
+ *     for (int i = 0, j = 0; i < size; ++i) {
+ *       elements[j++] = data[i];
+ *       elements[j++] = tags[i];
+ *     }
+ *   }
+ *
+ *   public Spliterator<T> spliterator() {
+ *     return new TaggedArraySpliterator<>(elements, 0, elements.length);
+ *   }
+ *
+ *   static class TaggedArraySpliterator<T> implements Spliterator<T> {
+ *     private final Object[] array;
+ *     private int origin; // current index, advanced on split or traversal
+ *     private final int fence; // one past the greatest index
+ *
+ *     TaggedArraySpliterator(Object[] array, int origin, int fence) {
+ *       this.array = array; this.origin = origin; this.fence = fence;
+ *     }
+ *
+ *     public void forEachRemaining(Consumer<? super T> action) {
+ *       for (; origin < fence; origin += 2)
+ *         action.accept((T) array[origin]);
+ *     }
+ *
+ *     public boolean tryAdvance(Consumer<? super T> action) {
+ *       if (origin < fence) {
+ *         action.accept((T) array[origin]);
+ *         origin += 2;
+ *         return true;
+ *       }
+ *       else // cannot advance
+ *         return false;
+ *     }
+ *
+ *     public Spliterator<T> trySplit() {
+ *       int lo = origin; // divide range in half
+ *       int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
+ *       if (lo < mid) { // split out left half
+ *         origin = mid; // reset this Spliterator's origin
+ *         return new TaggedArraySpliterator<>(array, lo, mid);
+ *       }
+ *       else       // too small to split
+ *         return null;
+ *     }
+ *
+ *     public long estimateSize() {
+ *       return (long)((fence - origin) / 2);
+ *     }
+ *
+ *     public int characteristics() {
+ *       return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>As an example how a parallel computation framework, such as the
+ * {@code java.util.stream} package, would use Spliterator in a parallel
+ * computation, here is one way to implement an associated parallel forEach,
+ * that illustrates the primary usage idiom of splitting off subtasks until
+ * the estimated amount of work is small enough to perform
+ * sequentially. Here we assume that the order of processing across
+ * subtasks doesn't matter; different (forked) tasks may further split
+ * and process elements concurrently in undetermined order.  This
+ * example uses a {@link java.util.concurrent.CountedCompleter};
+ * similar usages apply to other parallel task constructions.
+ *
+ * <pre>{@code
+ * static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
+ *   Spliterator<T> s = a.spliterator();
+ *   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
+ *   new ParEach(null, s, action, targetBatchSize).invoke();
+ * }
+ *
+ * static class ParEach<T> extends CountedCompleter<Void> {
+ *   final Spliterator<T> spliterator;
+ *   final Consumer<T> action;
+ *   final long targetBatchSize;
+ *
+ *   ParEach(ParEach<T> parent, Spliterator<T> spliterator,
+ *           Consumer<T> action, long targetBatchSize) {
+ *     super(parent);
+ *     this.spliterator = spliterator; this.action = action;
+ *     this.targetBatchSize = targetBatchSize;
+ *   }
+ *
+ *   public void compute() {
+ *     Spliterator<T> sub;
+ *     while (spliterator.estimateSize() > targetBatchSize &&
+ *            (sub = spliterator.trySplit()) != null) {
+ *       addToPendingCount(1);
+ *       new ParEach<>(this, sub, action, targetBatchSize).fork();
+ *     }
+ *     spliterator.forEachRemaining(action);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * @implNote
+ * If the boolean system property {@systemProperty org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this Spliterator
+ *
+ * @see Collection
+ * @since 1.8
+ */
+public interface Spliterator<T> {
+    /**
+     * If a remaining element exists, performs the given action on it,
+     * returning {@code true}; else returns {@code false}.  If this
+     * Spliterator is {@link #ORDERED} the action is performed on the
+     * next element in encounter order.  Exceptions thrown by the
+     * action are relayed to the caller.
+     * <p>
+     * Subsequent behavior of a spliterator is unspecified if the action throws
+     * an exception.
+     *
+     * @param action The action
+     * @return {@code false} if no remaining elements existed
+     * upon entry to this method, else {@code true}.
+     * @throws NullPointerException if the specified action is null
+     */
+    boolean tryAdvance(Consumer<? super T> action);
+
+    /**
+     * Performs the given action for each remaining element, sequentially in
+     * the current thread, until all elements have been processed or the action
+     * throws an exception.  If this Spliterator is {@link #ORDERED}, actions
+     * are performed in encounter order.  Exceptions thrown by the action
+     * are relayed to the caller.
+     * <p>
+     * Subsequent behavior of a spliterator is unspecified if the action throws
+     * an exception.
+     *
+     * @implSpec
+     * The default implementation repeatedly invokes {@link #tryAdvance} until
+     * it returns {@code false}.  It should be overridden whenever possible.
+     *
+     * @param action The action
+     * @throws NullPointerException if the specified action is null
+     */
+    default void forEachRemaining(Consumer<? super T> action) {
+        do { } while (tryAdvance(action));
+    }
+
+    /**
+     * If this spliterator can be partitioned, returns a Spliterator
+     * covering elements, that will, upon return from this method, not
+     * be covered by this Spliterator.
+     *
+     * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator
+     * must cover a strict prefix of the elements.
+     *
+     * <p>Unless this Spliterator covers an infinite number of elements,
+     * repeated calls to {@code trySplit()} must eventually return {@code null}.
+     * Upon non-null return:
+     * <ul>
+     * <li>the value reported for {@code estimateSize()} before splitting,
+     * must, after splitting, be greater than or equal to {@code estimateSize()}
+     * for this and the returned Spliterator; and</li>
+     * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
+     * for this spliterator before splitting must be equal to the sum of
+     * {@code estimateSize()} for this and the returned Spliterator after
+     * splitting.</li>
+     * </ul>
+     *
+     * <p>This method may return {@code null} for any reason,
+     * including emptiness, inability to split after traversal has
+     * commenced, data structure constraints, and efficiency
+     * considerations.
+     *
+     * @apiNote
+     * An ideal {@code trySplit} method efficiently (without
+     * traversal) divides its elements exactly in half, allowing
+     * balanced parallel computation.  Many departures from this ideal
+     * remain highly effective; for example, only approximately
+     * splitting an approximately balanced tree, or for a tree in
+     * which leaf nodes may contain either one or two elements,
+     * failing to further split these nodes.  However, large
+     * deviations in balance and/or overly inefficient {@code
+     * trySplit} mechanics typically result in poor parallel
+     * performance.
+     *
+     * @return a {@code Spliterator} covering some portion of the
+     * elements, or {@code null} if this spliterator cannot be split
+     */
+    Spliterator<T> trySplit();
+
+    /**
+     * Returns an estimate of the number of elements that would be
+     * encountered by a {@link #forEachRemaining} traversal, or returns {@link
+     * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute.
+     *
+     * <p>If this Spliterator is {@link #SIZED} and has not yet been partially
+     * traversed or split, or this Spliterator is {@link #SUBSIZED} and has
+     * not yet been partially traversed, this estimate must be an accurate
+     * count of elements that would be encountered by a complete traversal.
+     * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease
+     * as specified across invocations of {@link #trySplit}.
+     *
+     * @apiNote
+     * Even an inexact estimate is often useful and inexpensive to compute.
+     * For example, a sub-spliterator of an approximately balanced binary tree
+     * may return a value that estimates the number of elements to be half of
+     * that of its parent; if the root Spliterator does not maintain an
+     * accurate count, it could estimate size to be the power of two
+     * corresponding to its maximum depth.
+     *
+     * @return the estimated size, or {@code Long.MAX_VALUE} if infinite,
+     *         unknown, or too expensive to compute.
+     */
+    long estimateSize();
+
+    /**
+     * Convenience method that returns {@link #estimateSize()} if this
+     * Spliterator is {@link #SIZED}, else {@code -1}.
+     * @implSpec
+     * The default implementation returns the result of {@code estimateSize()}
+     * if the Spliterator reports a characteristic of {@code SIZED}, and
+     * {@code -1} otherwise.
+     *
+     * @return the exact size, if known, else {@code -1}.
+     */
+    default long getExactSizeIfKnown() {
+        return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
+    }
+
+    /**
+     * Returns a set of characteristics of this Spliterator and its
+     * elements. The result is represented as ORed values from {@link
+     * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED},
+     * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT},
+     * {@link #SUBSIZED}.  Repeated calls to {@code characteristics()} on
+     * a given spliterator, prior to or in-between calls to {@code trySplit},
+     * should always return the same result.
+     *
+     * <p>If a Spliterator reports an inconsistent set of
+     * characteristics (either those returned from a single invocation
+     * or across multiple invocations), no guarantees can be made
+     * about any computation using this Spliterator.
+     *
+     * @apiNote The characteristics of a given spliterator before splitting
+     * may differ from the characteristics after splitting.  For specific
+     * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED}
+     * and {@link #CONCURRENT}.
+     *
+     * @return a representation of characteristics
+     */
+    int characteristics();
+
+    /**
+     * Returns {@code true} if this Spliterator's {@link
+     * #characteristics} contain all of the given characteristics.
+     *
+     * @implSpec
+     * The default implementation returns true if the corresponding bits
+     * of the given characteristics are set.
+     *
+     * @param characteristics the characteristics to check for
+     * @return {@code true} if all the specified characteristics are present,
+     * else {@code false}
+     */
+    default boolean hasCharacteristics(int characteristics) {
+        return (characteristics() & characteristics) == characteristics;
+    }
+
+    /**
+     * If this Spliterator's source is {@link #SORTED} by a {@link Comparator},
+     * returns that {@code Comparator}. If the source is {@code SORTED} in
+     * {@linkplain Comparable natural order}, returns {@code null}.  Otherwise,
+     * if the source is not {@code SORTED}, throws {@link IllegalStateException}.
+     *
+     * @implSpec
+     * The default implementation always throws {@link IllegalStateException}.
+     *
+     * @return a Comparator, or {@code null} if the elements are sorted in the
+     * natural order.
+     * @throws IllegalStateException if the spliterator does not report
+     *         a characteristic of {@code SORTED}.
+     */
+    default Comparator<? super T> getComparator() {
+        throw new IllegalStateException();
+    }
+
+    /**
+     * Characteristic value signifying that an encounter order is defined for
+     * elements. If so, this Spliterator guarantees that method
+     * {@link #trySplit} splits a strict prefix of elements, that method
+     * {@link #tryAdvance} steps by one element in prefix order, and that
+     * {@link #forEachRemaining} performs actions in encounter order.
+     *
+     * <p>A {@link Collection} has an encounter order if the corresponding
+     * {@link Collection#iterator} documents an order. If so, the encounter
+     * order is the same as the documented order. Otherwise, a collection does
+     * not have an encounter order.
+     *
+     * @apiNote Encounter order is guaranteed to be ascending index order for
+     * any {@link List}. But no order is guaranteed for hash-based collections
+     * such as {@link HashSet}. Clients of a Spliterator that reports
+     * {@code ORDERED} are expected to preserve ordering constraints in
+     * non-commutative parallel computations.
+     */
+    public static final int ORDERED    = 0x00000010;
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements {@code x, y}, {@code !x.equals(y)}. This
+     * applies for example, to a Spliterator based on a {@link Set}.
+     */
+    public static final int DISTINCT   = 0x00000001;
+
+    /**
+     * Characteristic value signifying that encounter order follows a defined
+     * sort order. If so, method {@link #getComparator()} returns the associated
+     * Comparator, or {@code null} if all elements are {@link Comparable} and
+     * are sorted by their natural ordering.
+     *
+     * <p>A Spliterator that reports {@code SORTED} must also report
+     * {@code ORDERED}.
+     *
+     * @apiNote The spliterators for {@code Collection} classes in the JDK that
+     * implement {@link NavigableSet} or {@link SortedSet} report {@code SORTED}.
+     */
+    public static final int SORTED     = 0x00000004;
+
+    /**
+     * Characteristic value signifying that the value returned from
+     * {@code estimateSize()} prior to traversal or splitting represents a
+     * finite size that, in the absence of structural source modification,
+     * represents an exact count of the number of elements that would be
+     * encountered by a complete traversal.
+     *
+     * @apiNote Most Spliterators for Collections, that cover all elements of a
+     * {@code Collection} report this characteristic. Sub-spliterators, such as
+     * those for {@link HashSet}, that cover a sub-set of elements and
+     * approximate their reported size do not.
+     */
+    public static final int SIZED      = 0x00000040;
+
+    /**
+     * Characteristic value signifying that the source guarantees that
+     * encountered elements will not be {@code null}. (This applies,
+     * for example, to most concurrent collections, queues, and maps.)
+     */
+    public static final int NONNULL    = 0x00000100;
+
+    /**
+     * Characteristic value signifying that the element source cannot be
+     * structurally modified; that is, elements cannot be added, replaced, or
+     * removed, so such changes cannot occur during traversal. A Spliterator
+     * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected
+     * to have a documented policy (for example throwing
+     * {@link ConcurrentModificationException}) concerning structural
+     * interference detected during traversal.
+     */
+    public static final int IMMUTABLE  = 0x00000400;
+
+    /**
+     * Characteristic value signifying that the element source may be safely
+     * concurrently modified (allowing additions, replacements, and/or removals)
+     * by multiple threads without external synchronization. If so, the
+     * Spliterator is expected to have a documented policy concerning the impact
+     * of modifications during traversal.
+     *
+     * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
+     * {@code SIZED}, since the finite size, if known, may change if the source
+     * is concurrently modified during traversal. Such a Spliterator is
+     * inconsistent and no guarantees can be made about any computation using
+     * that Spliterator. Sub-spliterators may report {@code SIZED} if the
+     * sub-split size is known and additions or removals to the source are not
+     * reflected when traversing.
+     *
+     * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
+     * {@code IMMUTABLE}, since they are mutually exclusive. Such a Spliterator
+     * is inconsistent and no guarantees can be made about any computation using
+     * that Spliterator. Sub-spliterators may report {@code IMMUTABLE} if
+     * additions or removals to the source are not reflected when traversing.
+     *
+     * @apiNote Most concurrent collections maintain a consistency policy
+     * guaranteeing accuracy with respect to elements present at the point of
+     * Spliterator construction, but possibly not reflecting subsequent
+     * additions or removals.
+     */
+    public static final int CONCURRENT = 0x00001000;
+
+    /**
+     * Characteristic value signifying that all Spliterators resulting from
+     * {@code trySplit()} will be both {@link #SIZED} and {@link #SUBSIZED}.
+     * (This means that all child Spliterators, whether direct or indirect, will
+     * be {@code SIZED}.)
+     *
+     * <p>A Spliterator that does not report {@code SIZED} as required by
+     * {@code SUBSIZED} is inconsistent and no guarantees can be made about any
+     * computation using that Spliterator.
+     *
+     * @apiNote Some spliterators, such as the top-level spliterator for an
+     * approximately balanced binary tree, will report {@code SIZED} but not
+     * {@code SUBSIZED}, since it is common to know the size of the entire tree
+     * but not the exact sizes of subtrees.
+     */
+    public static final int SUBSIZED = 0x00004000;
+
+    /**
+     * A Spliterator specialized for primitive values.
+     *
+     * @param <T> the type of elements returned by this Spliterator.  The
+     * type must be a wrapper type for a primitive type, such as {@code Integer}
+     * for the primitive {@code int} type.
+     * @param <T_CONS> the type of primitive consumer.  The type must be a
+     * primitive specialization of {@link java.util.function.Consumer} for
+     * {@code T}, such as {@link java.util.function.IntConsumer} for
+     * {@code Integer}.
+     * @param <T_SPLITR> the type of primitive Spliterator.  The type must be
+     * a primitive specialization of Spliterator for {@code T}, such as
+     * {@link Spliterator.OfInt} for {@code Integer}.
+     *
+     * @see Spliterator.OfInt
+     * @see Spliterator.OfLong
+     * @see Spliterator.OfDouble
+     * @since 1.8
+     */
+    public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends Spliterator<T> {
+        @Override
+        T_SPLITR trySplit();
+
+        /**
+         * If a remaining element exists, performs the given action on it,
+         * returning {@code true}; else returns {@code false}.  If this
+         * Spliterator is {@link #ORDERED} the action is performed on the
+         * next element in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         * <p>
+         * Subsequent behavior of a spliterator is unspecified if the action throws
+         * an exception.
+         *
+         * @param action The action
+         * @return {@code false} if no remaining elements existed
+         * upon entry to this method, else {@code true}.
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        boolean tryAdvance(T_CONS action);
+
+        /**
+         * Performs the given action for each remaining element, sequentially in
+         * the current thread, until all elements have been processed or the
+         * action throws an exception.  If this Spliterator is {@link #ORDERED},
+         * actions are performed in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         * <p>
+         * Subsequent behavior of a spliterator is unspecified if the action throws
+         * an exception.
+         *
+         * @implSpec
+         * The default implementation repeatedly invokes {@link #tryAdvance}
+         * until it returns {@code false}.  It should be overridden whenever
+         * possible.
+         *
+         * @param action The action
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        default void forEachRemaining(T_CONS action) {
+            do { } while (tryAdvance(action));
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
+
+        @Override
+        OfInt trySplit();
+
+        @Override
+        boolean tryAdvance(IntConsumer action);
+
+        @Override
+        default void forEachRemaining(IntConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                return tryAdvance((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
+                return tryAdvance((IntConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
+
+        @Override
+        OfLong trySplit();
+
+        @Override
+        boolean tryAdvance(LongConsumer action);
+
+        @Override
+        default void forEachRemaining(LongConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                return tryAdvance((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
+                return tryAdvance((LongConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
+
+        @Override
+        OfDouble trySplit();
+
+        @Override
+        boolean tryAdvance(DoubleConsumer action);
+
+        @Override
+        default void forEachRemaining(DoubleConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}; otherwise
+         * the action is adapted to an instance of {@code DoubleConsumer}, by
+         * boxing the argument of {@code DoubleConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                return tryAdvance((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
+                return tryAdvance((DoubleConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)};
+         * otherwise the action is adapted to an instance of
+         * {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/Spliterators.java b/android-35/java/util/Spliterators.java
new file mode 100644
index 0000000..c5d9bd7
--- /dev/null
+++ b/android-35/java/util/Spliterators.java
@@ -0,0 +1,2168 @@
+/*
+ * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Static classes and methods for operating on or creating instances of
+ * {@link Spliterator} and its primitive specializations
+ * {@link Spliterator.OfInt}, {@link Spliterator.OfLong}, and
+ * {@link Spliterator.OfDouble}.
+ *
+ * @see Spliterator
+ * @since 1.8
+ */
+public final class Spliterators {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Spliterators() {}
+
+    // Empty spliterators
+
+    /**
+     * Creates an empty {@code Spliterator}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @param <T> Type of elements
+     * @return An empty spliterator
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Spliterator<T> emptySpliterator() {
+        return (Spliterator<T>) EMPTY_SPLITERATOR;
+    }
+
+    private static final Spliterator<Object> EMPTY_SPLITERATOR =
+            new EmptySpliterator.OfRef<>();
+
+    /**
+     * Creates an empty {@code Spliterator.OfInt}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfInt emptyIntSpliterator() {
+        return EMPTY_INT_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfInt EMPTY_INT_SPLITERATOR =
+            new EmptySpliterator.OfInt();
+
+    /**
+     * Creates an empty {@code Spliterator.OfLong}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfLong emptyLongSpliterator() {
+        return EMPTY_LONG_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfLong EMPTY_LONG_SPLITERATOR =
+            new EmptySpliterator.OfLong();
+
+    /**
+     * Creates an empty {@code Spliterator.OfDouble}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfDouble emptyDoubleSpliterator() {
+        return EMPTY_DOUBLE_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfDouble EMPTY_DOUBLE_SPLITERATOR =
+            new EmptySpliterator.OfDouble();
+
+    // Array-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(Object[])
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array,
+                                                 int additionalCharacteristics) {
+        return new ArraySpliterator<>(Objects.requireNonNull(array),
+                                      additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} covering a range of elements of a given
+     * array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(Object[], int, int)
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(int[])
+     */
+    public static Spliterator.OfInt spliterator(int[] array,
+                                                int additionalCharacteristics) {
+        return new IntArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(int[], int, int)
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex,
+                                                int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(long[])
+     */
+    public static Spliterator.OfLong spliterator(long[] array,
+                                                 int additionalCharacteristics) {
+        return new LongArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(long[], int, int)
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new LongArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(double[])
+     */
+    public static Spliterator.OfDouble spliterator(double[] array,
+                                                   int additionalCharacteristics) {
+        return new DoubleArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(double[], int, int)
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex,
+                                                   int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new DoubleArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Validate inclusive start index and exclusive end index against the length
+     * of an array.
+     * @param arrayLength The length of the array
+     * @param origin The inclusive start index
+     * @param fence The exclusive end index
+     * @throws ArrayIndexOutOfBoundsException if the start index is greater than
+     * the end index, if the start index is negative, or the end index is
+     * greater than the array length
+     */
+    private static void checkFromToBounds(int arrayLength, int origin, int fence) {
+        if (origin > fence) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "origin(" + origin + ") > fence(" + fence + ")");
+        }
+        if (origin < 0) {
+            throw new ArrayIndexOutOfBoundsException(origin);
+        }
+        if (fence > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(fence);
+        }
+    }
+
+    // Iterator-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} using the given collection's
+     * {@link java.util.Collection#iterator()} as the source of elements, and
+     * reporting its {@link java.util.Collection#size()} as its initial size.
+     *
+     * <p>The spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the collection's iterator, and
+     * implements {@code trySplit} to permit limited parallelism.
+     *
+     * @param <T> Type of elements
+     * @param c The collection
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given collection is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Collection<? extends T> c,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(c),
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, and with a given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Iterator<? extends T> iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size,
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, with no initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator,
+                                                            int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, and with a given
+     * initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator,
+                                                long size,
+                                                int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator),
+                                          size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, with no initial
+     * size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt iterator,
+                                                           int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator),
+                                           size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong iterator,
+                                                            int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator,
+                                                   long size,
+                                                   int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator),
+                                             size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble iterator,
+                                                              int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    // Iterators from Spliterators
+
+    /**
+     * Creates an {@code Iterator} from a {@code Spliterator}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static<T> Iterator<T> iterator(Spliterator<? extends T> spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements Iterator<T>, Consumer<T> {
+            boolean valueReady = false;
+            T nextElement;
+
+            @Override
+            public void accept(T t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public T next() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    T t = nextElement;
+                    nextElement = null;
+                    return t;
+                }
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+                if (valueReady) {
+                    valueReady = false;
+                    T t = nextElement;
+                    nextElement = null;
+                    action.accept(t);
+                }
+                spliterator.forEachRemaining(action);
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfInt} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfInt iterator(Spliterator.OfInt spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfInt, IntConsumer {
+            boolean valueReady = false;
+            int nextElement;
+
+            @Override
+            public void accept(int t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public int nextInt() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+
+            @Override
+            public void forEachRemaining(IntConsumer action) {
+                Objects.requireNonNull(action);
+                if (valueReady) {
+                    valueReady = false;
+                    action.accept(nextElement);
+                }
+                spliterator.forEachRemaining(action);
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfLong} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfLong iterator(Spliterator.OfLong spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfLong, LongConsumer {
+            boolean valueReady = false;
+            long nextElement;
+
+            @Override
+            public void accept(long t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public long nextLong() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+
+            @Override
+            public void forEachRemaining(LongConsumer action) {
+                Objects.requireNonNull(action);
+                if (valueReady) {
+                    valueReady = false;
+                    action.accept(nextElement);
+                }
+                spliterator.forEachRemaining(action);
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfDouble} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfDouble iterator(Spliterator.OfDouble spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfDouble, DoubleConsumer {
+            boolean valueReady = false;
+            double nextElement;
+
+            @Override
+            public void accept(double t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public double nextDouble() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+
+            @Override
+            public void forEachRemaining(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+                if (valueReady) {
+                    valueReady = false;
+                    action.accept(nextElement);
+                }
+                spliterator.forEachRemaining(action);
+            }
+        }
+
+        return new Adapter();
+    }
+
+    // Implementations
+
+    private abstract static class EmptySpliterator<T, S extends Spliterator<T>, C> {
+
+        EmptySpliterator() { }
+
+        public S trySplit() {
+            return null;
+        }
+
+        public boolean tryAdvance(C consumer) {
+            Objects.requireNonNull(consumer);
+            return false;
+        }
+
+        public void forEachRemaining(C consumer) {
+            Objects.requireNonNull(consumer);
+        }
+
+        public long estimateSize() {
+            return 0;
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static final class OfRef<T>
+                extends EmptySpliterator<T, Spliterator<T>, Consumer<? super T>>
+                implements Spliterator<T> {
+            OfRef() { }
+        }
+
+        private static final class OfInt
+                extends EmptySpliterator<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt() { }
+        }
+
+        private static final class OfLong
+                extends EmptySpliterator<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong() { }
+        }
+
+        private static final class OfDouble
+                extends EmptySpliterator<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble() { }
+        }
+    }
+
+    // Array-based spliterators
+
+    /**
+     * A Spliterator designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code Object[]} array.
+     */
+    static final class ArraySpliterator<T> implements Spliterator<T> {
+        /**
+         * The array, explicitly typed as Object[]. Unlike in some other
+         * classes (see for example CR 6260652), we do not need to
+         * screen arguments to ensure they are exactly of type Object[]
+         * so long as no methods write into the array or serialize it,
+         * which we ensure here by defining this class as final.
+         */
+        private final Object[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are always reported
+         */
+        public ArraySpliterator(Object[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are always reported
+         */
+        public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new ArraySpliterator<>(array, lo, index = mid, characteristics);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((T)a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                @SuppressWarnings("unchecked") T e = (T) array[index++];
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class IntArraySpliterator implements Spliterator.OfInt {
+        private final int[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public IntArraySpliterator(int[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new IntArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            int[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfLong designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class LongArraySpliterator implements Spliterator.OfLong {
+        private final long[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public LongArraySpliterator(long[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfLong trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new LongArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            long[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfDouble designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class DoubleArraySpliterator implements Spliterator.OfDouble {
+        private final double[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new DoubleArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            double[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    //
+
+    /**
+     * An abstract {@code Spliterator} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>An extending class need only
+     * implement {@link #tryAdvance(java.util.function.Consumer) tryAdvance}.
+     * The extending class should override
+     * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining}
+     * if it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(Iterator, long, int)}.  Depending on the
+     * circumstances using an iterator may be easier or more convenient than
+     * extending this class, such as when there is already an iterator
+     * available to use.
+     *
+     * @see #spliterator(Iterator, long, int)
+     * @since 1.8
+     */
+    public abstract static class AbstractSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * additionalCharacteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingConsumer<T> implements Consumer<T> {
+            Object value;
+
+            @Override
+            public void accept(T value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            HoldingConsumer<T> holder = new HoldingConsumer<>();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfInt} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.IntConsumer)
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.IntConsumer) forEachRemaining}
+     * if it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfInt, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfInt, long, int)
+     * @since 1.8
+     */
+    public abstract static class AbstractIntSpliterator implements Spliterator.OfInt {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractIntSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingIntConsumer implements IntConsumer {
+            int value;
+
+            @Override
+            public void accept(int value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfInt trySplit() {
+            HoldingIntConsumer holder = new HoldingIntConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfLong} that implements {@code trySplit}
+     * to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.LongConsumer)
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.LongConsumer) forEachRemaining}
+     * if it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfLong, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfLong, long, int)
+     * @since 1.8
+     */
+    public abstract static class AbstractLongSpliterator implements Spliterator.OfLong {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractLongSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingLongConsumer implements LongConsumer {
+            long value;
+
+            @Override
+            public void accept(long value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfLong trySplit() {
+            HoldingLongConsumer holder = new HoldingLongConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfDouble} that implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.DoubleConsumer)
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.DoubleConsumer) forEachRemaining}
+     * if it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)
+     * @since 1.8
+     */
+    public abstract static class AbstractDoubleSpliterator implements Spliterator.OfDouble {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractDoubleSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingDoubleConsumer implements DoubleConsumer {
+            double value;
+
+            @Override
+            public void accept(double value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            HoldingDoubleConsumer holder = new HoldingDoubleConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    // Iterator-based Spliterators
+
+    /**
+     * A Spliterator using a given Iterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static class IteratorSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final Collection<? extends T> collection; // null OK
+        private Iterator<? extends T> it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given
+         * collection's {@link java.util.Collection#iterator()) for traversal,
+         * and reporting its {@link java.util.Collection#size()) as its initial
+         * size.
+         *
+         * @param c the collection
+         * @param characteristics properties of this spliterator's
+         *        source or elements.
+         */
+        public IteratorSpliterator(Collection<? extends T> collection, int characteristics) {
+            this.collection = collection;
+            this.it = null;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, long size, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            Iterator<? extends T> i;
+            long s;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                s = est = (long) collection.size();
+            }
+            else
+                s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = i.next(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            Iterator<? extends T> i;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                est = (long)collection.size();
+            }
+            i.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            if (it == null) {
+                it = collection.iterator();
+                est = (long) collection.size();
+            }
+            if (it.hasNext()) {
+                action.accept(it.next());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            if (it == null) {
+                it = collection.iterator();
+                return est = (long)collection.size();
+            }
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt using a given IntStream.IntIterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static final class IntIteratorSpliterator implements Spliterator.OfInt {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private final PrimitiveIterator.OfInt it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfInt trySplit() {
+            PrimitiveIterator.OfInt i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = i.nextInt(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextInt());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class LongIteratorSpliterator implements Spliterator.OfLong {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private final PrimitiveIterator.OfLong it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfLong trySplit() {
+            PrimitiveIterator.OfLong i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = i.nextLong(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextLong());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private final PrimitiveIterator.OfDouble it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            PrimitiveIterator.OfDouble i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = i.nextDouble(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextDouble());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+}
diff --git a/android-35/java/util/SplittableRandom.java b/android-35/java/util/SplittableRandom.java
new file mode 100644
index 0000000..f3dd55a
--- /dev/null
+++ b/android-35/java/util/SplittableRandom.java
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.random.RandomGenerator;
+import java.util.random.RandomGenerator.SplittableGenerator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import jdk.internal.util.random.RandomSupport;
+import jdk.internal.util.random.RandomSupport.AbstractSplittableGenerator;
+import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
+
+/**
+ * A generator of uniform pseudorandom values (with period 2<sup>64</sup>)
+ * applicable for use in (among other contexts) isolated parallel
+ * computations that may generate subtasks. Class {@code SplittableRandom}
+ * supports methods for producing pseudorandom numbers of type {@code int},
+ * {@code long}, and {@code double} with similar usages as for class
+ * {@link java.util.Random} but differs in the following ways:
+ *
+ * <ul>
+ *
+ * <li>Series of generated values pass the DieHarder suite testing
+ * independence and uniformity properties of random number generators.
+ * (Most recently validated with <a
+ * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
+ * 3.31.1</a>.) These tests validate only the methods for certain
+ * types and ranges, but similar properties are expected to hold, at
+ * least approximately, for others as well. The <em>period</em>
+ * (length of any series of generated values before it repeats) is
+ * 2<sup>64</sup>. </li>
+ *
+ * <li> Method {@link #split} constructs and returns a new
+ * SplittableRandom instance that shares no mutable state with the
+ * current instance. However, with very high probability, the
+ * values collectively generated by the two objects have the same
+ * statistical properties as if the same quantity of values were
+ * generated by a single thread using a single {@code
+ * SplittableRandom} object.  </li>
+ *
+ * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
+ * They are designed to be split, not shared, across threads. For
+ * example, a {@link java.util.concurrent.ForkJoinTask
+ * fork/join-style} computation using random numbers might include a
+ * construction of the form {@code new
+ * Subtask(aSplittableRandom.split()).fork()}.
+ *
+ * <li>This class provides additional methods for generating random
+ * streams, that employ the above techniques when used in {@code
+ * stream.parallel()} mode.</li>
+ *
+ * </ul>
+ *
+ * <p>Instances of {@code SplittableRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @author  Guy Steele
+ * @author  Doug Lea
+ * @since   1.8
+ */
+@RandomGeneratorProperties(
+        name = "SplittableRandom",
+        i = 64, j = 0, k = 0,
+        equidistribution = 1
+)
+public final class SplittableRandom implements RandomGenerator, SplittableGenerator {
+
+    /*
+     * Implementation Overview.
+     *
+     * This algorithm was inspired by the "DotMix" algorithm by
+     * Leiserson, Schardl, and Sukha "Deterministic Parallel
+     * Random-Number Generation for Dynamic-Multithreading Platforms",
+     * PPoPP 2012, as well as those in "Parallel random numbers: as
+     * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011.  It
+     * differs mainly in simplifying and cheapening operations.
+     *
+     * The primary update step (method nextSeed()) is to add a
+     * constant ("gamma") to the current (64 bit) seed, forming a
+     * simple sequence.  The seed and the gamma values for any two
+     * SplittableRandom instances are highly likely to be different.
+     *
+     * Methods nextLong, nextInt, and derivatives do not return the
+     * sequence (seed) values, but instead a hash-like bit-mix of
+     * their bits, producing more independently distributed sequences.
+     * For nextLong, the mix64 function is based on David Stafford's
+     * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
+     * "Mix13" variant of the "64-bit finalizer" function in Austin
+     * Appleby's MurmurHash3 algorithm (see
+     * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32
+     * function is based on Stafford's Mix04 mix function, but returns
+     * the upper 32 bits cast as int.
+     *
+     * The split operation uses the current generator to form the seed
+     * and gamma for another SplittableRandom.  To conservatively
+     * avoid potential correlations between seed and value generation,
+     * gamma selection (method mixGamma) uses different
+     * (Murmurhash3's) mix constants.  To avoid potential weaknesses
+     * in bit-mixing transformations, we restrict gammas to odd values
+     * with at least 24 0-1 or 1-0 bit transitions.  Rather than
+     * rejecting candidates with too few or too many bits set, method
+     * mixGamma flips some bits (which has the effect of mapping at
+     * most 4 to any given gamma value).  This reduces the effective
+     * set of 64bit odd gamma values by about 2%, and serves as an
+     * automated screening for sequence constant selection that is
+     * left as an empirical decision in some other hashing and crypto
+     * algorithms.
+     *
+     * The resulting generator thus transforms a sequence in which
+     * (typically) many bits change on each step, with an inexpensive
+     * mixer with good (but less than cryptographically secure)
+     * avalanching.
+     *
+     * The default (no-argument) constructor, in essence, invokes
+     * split() for a common "defaultGen" SplittableRandom.  Unlike
+     * other cases, this split must be performed in a thread-safe
+     * manner, so we use an AtomicLong to represent the seed rather
+     * than use an explicit SplittableRandom. To bootstrap the
+     * defaultGen, we start off using a seed based on current time
+     * unless the java.util.secureRandomSeed property is set. This
+     * serves as a slimmed-down (and insecure) variant of SecureRandom
+     * that also avoids stalls that may occur when using /dev/random.
+     *
+     * It is a relatively simple matter to apply the basic design here
+     * to use 128 bit seeds. However, emulating 128bit arithmetic and
+     * carrying around twice the state add more overhead than appears
+     * warranted for current usages.
+     *
+     * File organization: First the non-public methods that constitute
+     * the main algorithm, then the main public methods, followed by
+     * some custom spliterator classes needed for stream methods.
+     */
+
+    /**
+     * The golden ratio scaled to 64bits, used as the initial gamma
+     * value for (unsplit) SplittableRandoms.
+     */
+    private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The seed. Updated only via method nextSeed.
+     */
+    private long seed;
+
+    /**
+     * The step value.
+     */
+    private final long gamma;
+
+    /**
+     * Internal constructor used by all others except default constructor.
+     */
+    private SplittableRandom(long seed, long gamma) {
+        this.seed = seed;
+        this.gamma = gamma;
+        this.proxy = new AbstractSplittableGeneratorProxy();
+    }
+
+    /**
+     * Computes Stafford variant 13 of 64bit mix function.
+     * http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
+     */
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
+        z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
+        return z ^ (z >>> 31);
+    }
+
+    /**
+     * Returns the 32 high bits of Stafford variant 4 mix64 function as int.
+     * http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
+     */
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
+        return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
+    }
+
+    /**
+     * Returns the gamma value to use for a new split instance.
+     * Uses the 64bit mix function from MurmurHash3.
+     * https://github.com/aappleby/smhasher/wiki/MurmurHash3
+     */
+    private static long mixGamma(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        z = (z ^ (z >>> 33)) | 1L;                  // force to be odd
+        int n = Long.bitCount(z ^ (z >>> 1));       // ensure enough transitions
+        return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
+    }
+
+    /**
+     * Proxy class to non-public RandomSupportAbstractSplittableGenerator.
+     */
+    private class AbstractSplittableGeneratorProxy extends AbstractSplittableGenerator {
+        @Override
+        public int nextInt() {
+            return SplittableRandom.this.nextInt();
+        }
+
+        @Override
+        public long nextLong() {
+            return SplittableRandom.this.nextLong();
+        }
+
+        @Override
+        public java.util.SplittableRandom split(SplittableGenerator source) {
+            return new SplittableRandom(source.nextLong(), mixGamma(source.nextLong()));
+        }
+    }
+
+    /**
+     * Proxy object to non-public RandomSupportAbstractSplittableGenerator.
+     */
+    private AbstractSplittableGeneratorProxy proxy;
+
+    /**
+     * Adds gamma to seed.
+     */
+    private long nextSeed() {
+        return seed += gamma;
+    }
+
+    /**
+     * The seed generator for default constructors.
+     */
+    private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
+
+    /* ---------------- public methods ---------------- */
+
+    /**
+     * Creates a new SplittableRandom instance using the specified
+     * initial seed. SplittableRandom instances created with the same
+     * seed in the same program generate identical sequences of values.
+     *
+     * @param seed the initial seed
+     */
+    public SplittableRandom(long seed) {
+        this(seed, GOLDEN_GAMMA);
+    }
+
+    /**
+     * Creates a new SplittableRandom instance that is likely to
+     * generate sequences of values that are statistically independent
+     * of those of any other instances in the current program; and
+     * may, and typically does, vary across program invocations.
+     */
+    public SplittableRandom() { // emulate defaultGen.split()
+        long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA);
+        this.seed = mix64(s);
+        this.gamma = mixGamma(s + GOLDEN_GAMMA);
+        this.proxy = new AbstractSplittableGeneratorProxy();
+    }
+
+    /**
+     * Constructs and returns a new SplittableRandom instance that
+     * shares no mutable state with this instance. However, with very
+     * high probability, the set of values collectively generated by
+     * the two objects has the same statistical properties as if the
+     * same quantity of values were generated by a single thread using
+     * a single SplittableRandom object.  Either or both of the two
+     * objects may be further split using the {@code split()} method,
+     * and the same expected statistical properties apply to the
+     * entire set of generators constructed by such recursive
+     * splitting.
+     *
+     * @return the new SplittableRandom instance
+     */
+    public SplittableRandom split() {
+        return new SplittableRandom(nextLong(), mixGamma(nextSeed()));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 17
+     */
+    public SplittableRandom split(SplittableGenerator source) {
+        return new SplittableRandom(source.nextLong(), mixGamma(source.nextLong()));
+    }
+
+    @Override
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    @Override
+    public long nextLong() {
+        return mix64(nextSeed());
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 10
+     */
+    @Override
+    public void nextBytes(byte[] bytes) {
+        proxy.nextBytes(bytes);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implSpec {@inheritDoc}
+     * @since 17
+     */
+    @Override
+    public Stream<SplittableGenerator> splits() {
+        return proxy.splits();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implSpec {@inheritDoc}
+     * @since 17
+     */
+    @Override
+    public Stream<SplittableGenerator> splits(long streamSize) {
+        return proxy.splits(streamSize, this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @implSpec {@inheritDoc}
+     * @since 17
+     */
+    @Override
+    public Stream<SplittableGenerator> splits(SplittableGenerator source) {
+        return proxy.splits(Long.MAX_VALUE, source);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implSpec {@inheritDoc}
+     * @since 17
+     */
+    @Override
+    public Stream<SplittableGenerator> splits(long streamSize, SplittableGenerator source) {
+        return proxy.splits(streamSize, source);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public IntStream ints(long streamSize) {
+        return proxy.ints(streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     */
+    @Override
+    public IntStream ints() {
+        return proxy.ints();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) {
+        return proxy.ints(streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        return proxy.ints(randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code long} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public LongStream longs(long streamSize) {
+        return proxy.longs(streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     */
+    @Override
+    public LongStream longs() {
+        return proxy.longs();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public LongStream longs(long streamSize, long randomNumberOrigin, long randomNumberBound) {
+        return proxy.longs(streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        return proxy.longs(randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value is between zero (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public DoubleStream doubles(long streamSize) {
+        return proxy.doubles(streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * is between zero (inclusive) and one (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     */
+    @Override
+    public DoubleStream doubles() {
+        return proxy.doubles();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
+        return proxy.doubles(streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        return proxy.doubles(randomNumberOrigin, randomNumberBound);
+    }
+}
diff --git a/android-35/java/util/Stack.java b/android-35/java/util/Stack.java
new file mode 100644
index 0000000..b807d73
--- /dev/null
+++ b/android-35/java/util/Stack.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The {@code Stack} class represents a last-in-first-out
+ * (LIFO) stack of objects. It extends class {@code Vector} with five
+ * operations that allow a vector to be treated as a stack. The usual
+ * {@code push} and {@code pop} operations are provided, as well as a
+ * method to {@code peek} at the top item on the stack, a method to test
+ * for whether the stack is {@code empty}, and a method to {@code search}
+ * the stack for an item and discover how far it is from the top.
+ * <p>
+ * When a stack is first created, it contains no items.
+ *
+ * <p>A more complete and consistent set of LIFO stack operations is
+ * provided by the {@link Deque} interface and its implementations, which
+ * should be used in preference to this class.  For example:
+ * <pre>   {@code
+ *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
+ *
+ * @author  Jonathan Payne
+ * @since   1.0
+ */
+public class Stack<E> extends Vector<E> {
+    /**
+     * Creates an empty Stack.
+     */
+    public Stack() {
+    }
+
+    /**
+     * Pushes an item onto the top of this stack. This has exactly
+     * the same effect as:
+     * <blockquote><pre>
+     * addElement(item)</pre></blockquote>
+     *
+     * @param   item   the item to be pushed onto this stack.
+     * @return  the {@code item} argument.
+     * @see     java.util.Vector#addElement
+     */
+    public E push(E item) {
+        addElement(item);
+
+        return item;
+    }
+
+    /**
+     * Removes the object at the top of this stack and returns that
+     * object as the value of this function.
+     *
+     * @return  The object at the top of this stack (the last item
+     *          of the {@code Vector} object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E pop() {
+        E       obj;
+        int     len = size();
+
+        obj = peek();
+        removeElementAt(len - 1);
+
+        return obj;
+    }
+
+    /**
+     * Looks at the object at the top of this stack without removing it
+     * from the stack.
+     *
+     * @return  the object at the top of this stack (the last item
+     *          of the {@code Vector} object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E peek() {
+        int     len = size();
+
+        if (len == 0)
+            throw new EmptyStackException();
+        return elementAt(len - 1);
+    }
+
+    /**
+     * Tests if this stack is empty.
+     *
+     * @return  {@code true} if and only if this stack contains
+     *          no items; {@code false} otherwise.
+     */
+    public boolean empty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the 1-based position where an object is on this stack.
+     * If the object {@code o} occurs as an item in this stack, this
+     * method returns the distance from the top of the stack of the
+     * occurrence nearest the top of the stack; the topmost item on the
+     * stack is considered to be at distance {@code 1}. The {@code equals}
+     * method is used to compare {@code o} to the
+     * items in this stack.
+     *
+     * @param   o   the desired object.
+     * @return  the 1-based position from the top of the stack where
+     *          the object is located; the return value {@code -1}
+     *          indicates that the object is not on the stack.
+     */
+    public synchronized int search(Object o) {
+        int i = lastIndexOf(o);
+
+        if (i >= 0) {
+            return size() - i;
+        }
+        return -1;
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    @java.io.Serial
+    private static final long serialVersionUID = 1224463164541339165L;
+}
diff --git a/android-35/java/util/StringJoiner.java b/android-35/java/util/StringJoiner.java
new file mode 100644
index 0000000..c72d5a2
--- /dev/null
+++ b/android-35/java/util/StringJoiner.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * {@code StringJoiner} is used to construct a sequence of characters separated
+ * by a delimiter and optionally starting with a supplied prefix
+ * and ending with a supplied suffix.
+ * <p>
+ * Prior to adding something to the {@code StringJoiner}, its
+ * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
+ * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
+ * supplied will be returned instead. This can be used, for example, when
+ * creating a string using set notation to indicate an empty set, i.e.
+ * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
+ * {@code suffix} is <code>"}"</code> and nothing has been added to the
+ * {@code StringJoiner}.
+ *
+ * @apiNote
+ * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
+ *
+ * <pre> {@code
+ * StringJoiner sj = new StringJoiner(":", "[", "]");
+ * sj.add("George").add("Sally").add("Fred");
+ * String desiredString = sj.toString();
+ * }</pre>
+ * <p>
+ * A {@code StringJoiner} may be employed to create formatted output from a
+ * {@link java.util.stream.Stream} using
+ * {@link java.util.stream.Collectors#joining(CharSequence)}. For example:
+ *
+ * <pre> {@code
+ * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
+ * String commaSeparatedNumbers = numbers.stream()
+ *     .map(i -> i.toString())
+ *     .collect(Collectors.joining(", "));
+ * }</pre>
+ *
+ * @see java.util.stream.Collectors#joining(CharSequence)
+ * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
+ * @since  1.8
+*/
+public final class StringJoiner {
+    private final String prefix;
+    private final String delimiter;
+    private final String suffix;
+
+    /** Contains all the string components added so far. */
+    private String[] elts;
+
+    /** The number of string components added so far. */
+    private int size;
+
+    /** Total length in chars so far, excluding prefix and suffix. */
+    private int len;
+
+    /**
+     * When overriden by the user to be non-null via {@link setEmptyValue}, the
+     * string returned by toString() when no elements have yet been added.
+     * When null, prefix + suffix is used as the empty value.
+     */
+    private String emptyValue;
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it, with no
+     * {@code prefix} or {@code suffix}, and a copy of the supplied
+     * {@code delimiter}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the value of it are invoked, it will not return a
+     * {@code prefix} or {@code suffix} (or properties thereof) in the result,
+     * unless {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner} value
+     * @throws NullPointerException if {@code delimiter} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter) {
+        this(delimiter, "", "");
+    }
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it using copies
+     * of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the string value of it are invoked, it will return the
+     * {@code prefix + suffix} (or properties thereof) in the result, unless
+     * {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner}
+     * @param  prefix the sequence of characters to be used at the beginning
+     * @param  suffix the sequence of characters to be used at the end
+     * @throws NullPointerException if {@code prefix}, {@code delimiter}, or
+     *         {@code suffix} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter,
+                        CharSequence prefix,
+                        CharSequence suffix) {
+        Objects.requireNonNull(prefix, "The prefix must not be null");
+        Objects.requireNonNull(delimiter, "The delimiter must not be null");
+        Objects.requireNonNull(suffix, "The suffix must not be null");
+        // make defensive copies of arguments
+        this.prefix = prefix.toString();
+        this.delimiter = delimiter.toString();
+        this.suffix = suffix.toString();
+    }
+
+    /**
+     * Sets the sequence of characters to be used when determining the string
+     * representation of this {@code StringJoiner} and no elements have been
+     * added yet, that is, when it is empty.  A copy of the {@code emptyValue}
+     * parameter is made for this purpose. Note that once an add method has been
+     * called, the {@code StringJoiner} is no longer considered empty, even if
+     * the element(s) added correspond to the empty {@code String}.
+     *
+     * @param  emptyValue the characters to return as the value of an empty
+     *         {@code StringJoiner}
+     * @return this {@code StringJoiner} itself so the calls may be chained
+     * @throws NullPointerException when the {@code emptyValue} parameter is
+     *         {@code null}
+     */
+    public StringJoiner setEmptyValue(CharSequence emptyValue) {
+        this.emptyValue = Objects.requireNonNull(emptyValue,
+            "The empty value must not be null").toString();
+        return this;
+    }
+
+    private static int getChars(String s, char[] chars, int start) {
+        int len = s.length();
+        s.getChars(0, len, chars, start);
+        return len;
+    }
+
+    /**
+     * Returns the current value, consisting of the {@code prefix}, the values
+     * added so far separated by the {@code delimiter}, and the {@code suffix},
+     * unless no elements have been added in which case, the
+     * {@code prefix + suffix} or the {@code emptyValue} characters are returned.
+     *
+     * @return the string representation of this {@code StringJoiner}
+     */
+    @Override
+    public String toString() {
+        final String[] elts = this.elts;
+        if (elts == null && emptyValue != null) {
+            return emptyValue;
+        }
+        final int size = this.size;
+        final int addLen = prefix.length() + suffix.length();
+        if (addLen == 0) {
+            compactElts();
+            return size == 0 ? "" : elts[0];
+        }
+        final String delimiter = this.delimiter;
+        final char[] chars = new char[len + addLen];
+        int k = getChars(prefix, chars, 0);
+        if (size > 0) {
+            k += getChars(elts[0], chars, k);
+            for (int i = 1; i < size; i++) {
+                k += getChars(delimiter, chars, k);
+                k += getChars(elts[i], chars, k);
+            }
+        }
+        k += getChars(suffix, chars, k);
+        return new String(chars);
+    }
+
+    /**
+     * Adds a copy of the given {@code CharSequence} value as the next
+     * element of the {@code StringJoiner} value. If {@code newElement} is
+     * {@code null}, then {@code "null"} is added.
+     *
+     * @param  newElement The element to add
+     * @return a reference to this {@code StringJoiner}
+     */
+    public StringJoiner add(CharSequence newElement) {
+        final String elt = String.valueOf(newElement);
+        if (elts == null) {
+            elts = new String[8];
+        } else {
+            if (size == elts.length)
+                elts = Arrays.copyOf(elts, 2 * size);
+            len += delimiter.length();
+        }
+        len += elt.length();
+        elts[size++] = elt;
+        return this;
+    }
+
+    /**
+     * Adds the contents of the given {@code StringJoiner} without prefix and
+     * suffix as the next element if it is non-empty. If the given {@code
+     * StringJoiner} is empty, the call has no effect.
+     *
+     * <p>A {@code StringJoiner} is empty if {@link #add(CharSequence) add()}
+     * has never been called, and if {@code merge()} has never been called
+     * with a non-empty {@code StringJoiner} argument.
+     *
+     * <p>If the other {@code StringJoiner} is using a different delimiter,
+     * then elements from the other {@code StringJoiner} are concatenated with
+     * that delimiter and the result is appended to this {@code StringJoiner}
+     * as a single element.
+     *
+     * @param other The {@code StringJoiner} whose contents should be merged
+     *              into this one
+     * @throws NullPointerException if the other {@code StringJoiner} is null
+     * @return This {@code StringJoiner}
+     */
+    public StringJoiner merge(StringJoiner other) {
+        Objects.requireNonNull(other);
+        if (other.elts == null) {
+            return this;
+        }
+        other.compactElts();
+        return add(other.elts[0]);
+    }
+
+    private void compactElts() {
+        if (size > 1) {
+            final char[] chars = new char[len];
+            int i = 1, k = getChars(elts[0], chars, 0);
+            do {
+                k += getChars(delimiter, chars, k);
+                k += getChars(elts[i], chars, k);
+                elts[i] = null;
+            } while (++i < size);
+            size = 1;
+            elts[0] = new String(chars);
+        }
+    }
+
+    /**
+     * Returns the length of the {@code String} representation
+     * of this {@code StringJoiner}. Note that if
+     * no add methods have been called, then the length of the {@code String}
+     * representation (either {@code prefix + suffix} or {@code emptyValue})
+     * will be returned. The value should be equivalent to
+     * {@code toString().length()}.
+     *
+     * @return the length of the current value of {@code StringJoiner}
+     */
+    public int length() {
+        return (size == 0 && emptyValue != null) ? emptyValue.length() :
+            len + prefix.length() + suffix.length();
+    }
+}
diff --git a/android-35/java/util/StringTokenizer.java b/android-35/java/util/StringTokenizer.java
new file mode 100644
index 0000000..f30f7b8
--- /dev/null
+++ b/android-35/java/util/StringTokenizer.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.*;
+
+/**
+ * The string tokenizer class allows an application to break a
+ * string into tokens. The tokenization method is much simpler than
+ * the one used by the {@code StreamTokenizer} class. The
+ * {@code StringTokenizer} methods do not distinguish among
+ * identifiers, numbers, and quoted strings, nor do they recognize
+ * and skip comments.
+ * <p>
+ * The set of delimiters (the characters that separate tokens) may
+ * be specified either at creation time or on a per-token basis.
+ * <p>
+ * An instance of {@code StringTokenizer} behaves in one of two
+ * ways, depending on whether it was created with the
+ * {@code returnDelims} flag having the value {@code true}
+ * or {@code false}:
+ * <ul>
+ * <li>If the flag is {@code false}, delimiter characters serve to
+ *     separate tokens. A token is a maximal sequence of consecutive
+ *     characters that are not delimiters.
+ * <li>If the flag is {@code true}, delimiter characters are themselves
+ *     considered to be tokens. A token is thus either one delimiter
+ *     character, or a maximal sequence of consecutive characters that are
+ *     not delimiters.
+ * </ul><p>
+ * A {@code StringTokenizer} object internally maintains a current
+ * position within the string to be tokenized. Some operations advance this
+ * current position past the characters processed.<p>
+ * A token is returned by taking a substring of the string that was used to
+ * create the {@code StringTokenizer} object.
+ * <p>
+ * The following is one example of the use of the tokenizer. The code:
+ * <blockquote><pre>
+ *     StringTokenizer st = new StringTokenizer("this is a test");
+ *     while (st.hasMoreTokens()) {
+ *         System.out.println(st.nextToken());
+ *     }
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * <p>
+ * {@code StringTokenizer} is a legacy class that is retained for
+ * compatibility reasons although its use is discouraged in new code. It is
+ * recommended that anyone seeking this functionality use the {@code split}
+ * method of {@code String} or the java.util.regex package instead.
+ * <p>
+ * The following example illustrates how the {@code String.split}
+ * method can be used to break up a string into its basic tokens:
+ * <blockquote><pre>
+ *     String[] result = "this is a test".split("\\s");
+ *     for (int x=0; x&lt;result.length; x++)
+ *         System.out.println(result[x]);
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * @see     java.io.StreamTokenizer
+ * @since   1.0
+ */
+public class StringTokenizer implements Enumeration<Object> {
+    private int currentPosition;
+    private int newPosition;
+    private int maxPosition;
+    private String str;
+    private String delimiters;
+    private boolean retDelims;
+    private boolean delimsChanged;
+
+    /**
+     * maxDelimCodePoint stores the value of the delimiter character with the
+     * highest value. It is used to optimize the detection of delimiter
+     * characters.
+     *
+     * It is unlikely to provide any optimization benefit in the
+     * hasSurrogates case because most string characters will be
+     * smaller than the limit, but we keep it so that the two code
+     * paths remain similar.
+     */
+    private int maxDelimCodePoint;
+
+    /**
+     * If delimiters include any surrogates (including surrogate
+     * pairs), hasSurrogates is true and the tokenizer uses the
+     * different code path. This is because String.indexOf(int)
+     * doesn't handle unpaired surrogates as a single character.
+     */
+    private boolean hasSurrogates = false;
+
+    /**
+     * When hasSurrogates is true, delimiters are converted to code
+     * points and isDelimiter(int) is used to determine if the given
+     * codepoint is a delimiter.
+     */
+    private int[] delimiterCodePoints;
+
+    /**
+     * Set maxDelimCodePoint to the highest char in the delimiter set.
+     */
+    private void setMaxDelimCodePoint() {
+        if (delimiters == null) {
+            maxDelimCodePoint = 0;
+            return;
+        }
+
+        int m = 0;
+        int c;
+        int count = 0;
+        for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
+            c = delimiters.charAt(i);
+            if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
+                c = delimiters.codePointAt(i);
+                hasSurrogates = true;
+            }
+            if (m < c)
+                m = c;
+            count++;
+        }
+        maxDelimCodePoint = m;
+
+        if (hasSurrogates) {
+            delimiterCodePoints = new int[count];
+            for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
+                c = delimiters.codePointAt(j);
+                delimiterCodePoints[i] = c;
+            }
+        }
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. All
+     * characters in the {@code delim} argument are the delimiters
+     * for separating tokens.
+     * <p>
+     * If the {@code returnDelims} flag is {@code true}, then
+     * the delimiter characters are also returned as tokens. Each
+     * delimiter is returned as a string of length one. If the flag is
+     * {@code false}, the delimiter characters are skipped and only
+     * serve as separators between tokens.
+     * <p>
+     * Note that if {@code delim} is {@code null}, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting {@code StringTokenizer} may result in a
+     * {@code NullPointerException}.
+     *
+     * @param   str            a string to be parsed.
+     * @param   delim          the delimiters.
+     * @param   returnDelims   flag indicating whether to return the delimiters
+     *                         as tokens.
+     * @throws    NullPointerException if str is {@code null}
+     */
+    public StringTokenizer(String str, String delim, boolean returnDelims) {
+        currentPosition = 0;
+        newPosition = -1;
+        delimsChanged = false;
+        this.str = str;
+        maxPosition = str.length();
+        delimiters = delim;
+        retDelims = returnDelims;
+        setMaxDelimCodePoint();
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * characters in the {@code delim} argument are the delimiters
+     * for separating tokens. Delimiter characters themselves will not
+     * be treated as tokens.
+     * <p>
+     * Note that if {@code delim} is {@code null}, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting {@code StringTokenizer} may result in a
+     * {@code NullPointerException}.
+     *
+     * @param   str     a string to be parsed.
+     * @param   delim   the delimiters.
+     * @throws    NullPointerException if str is {@code null}
+     */
+    public StringTokenizer(String str, String delim) {
+        this(str, delim, false);
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * tokenizer uses the default delimiter set, which is
+     * <code>"&nbsp;&#92;t&#92;n&#92;r&#92;f"</code>: the space character,
+     * the tab character, the newline character, the carriage-return character,
+     * and the form-feed character. Delimiter characters themselves will
+     * not be treated as tokens.
+     *
+     * @param   str   a string to be parsed.
+     * @throws    NullPointerException if str is {@code null}
+     */
+    public StringTokenizer(String str) {
+        this(str, " \t\n\r\f", false);
+    }
+
+    /**
+     * Skips delimiters starting from the specified position. If retDelims
+     * is false, returns the index of the first non-delimiter character at or
+     * after startPos. If retDelims is true, startPos is returned.
+     */
+    private int skipDelimiters(int startPos) {
+        if (delimiters == null)
+            throw new NullPointerException();
+
+        int position = startPos;
+        while (!retDelims && position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
+                    break;
+                }
+                position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    /**
+     * Skips ahead from startPos and returns the index of the next delimiter
+     * character encountered, or maxPosition if no such delimiter is found.
+     */
+    private int scanToken(int startPos) {
+        int position = startPos;
+        while (position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    break;
+                position += Character.charCount(c);
+            }
+        }
+        if (retDelims && (startPos == position)) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    private boolean isDelimiter(int codePoint) {
+        for (int delimiterCodePoint : delimiterCodePoints) {
+            if (delimiterCodePoint == codePoint) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests if there are more tokens available from this tokenizer's string.
+     * If this method returns {@code true}, then a subsequent call to
+     * {@code nextToken} with no argument will successfully return a token.
+     *
+     * @return  {@code true} if and only if there is at least one token
+     *          in the string after the current position; {@code false}
+     *          otherwise.
+     */
+    public boolean hasMoreTokens() {
+        /*
+         * Temporarily store this position and use it in the following
+         * nextToken() method only if the delimiters haven't been changed in
+         * that nextToken() invocation.
+         */
+        newPosition = skipDelimiters(currentPosition);
+        return (newPosition < maxPosition);
+    }
+
+    /**
+     * Returns the next token from this string tokenizer.
+     *
+     * @return     the next token from this string tokenizer.
+     * @throws     NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     */
+    public String nextToken() {
+        /*
+         * If next position already computed in hasMoreElements() and
+         * delimiters have changed between the computation and this invocation,
+         * then use the computed value.
+         */
+
+        currentPosition = (newPosition >= 0 && !delimsChanged) ?
+            newPosition : skipDelimiters(currentPosition);
+
+        /* Reset these anyway */
+        delimsChanged = false;
+        newPosition = -1;
+
+        if (currentPosition >= maxPosition)
+            throw new NoSuchElementException();
+        int start = currentPosition;
+        currentPosition = scanToken(currentPosition);
+        return str.substring(start, currentPosition);
+    }
+
+    /**
+     * Returns the next token in this string tokenizer's string. First,
+     * the set of characters considered to be delimiters by this
+     * {@code StringTokenizer} object is changed to be the characters in
+     * the string {@code delim}. Then the next token in the string
+     * after the current position is returned. The current position is
+     * advanced beyond the recognized token.  The new delimiter set
+     * remains the default after this call.
+     *
+     * @param      delim   the new delimiters.
+     * @return     the next token, after switching to the new delimiter set.
+     * @throws     NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @throws    NullPointerException if delim is {@code null}
+     */
+    public String nextToken(String delim) {
+        delimiters = delim;
+
+        /* delimiter string specified, so set the appropriate flag. */
+        delimsChanged = true;
+
+        setMaxDelimCodePoint();
+        return nextToken();
+    }
+
+    /**
+     * Returns the same value as the {@code hasMoreTokens}
+     * method. It exists so that this class can implement the
+     * {@code Enumeration} interface.
+     *
+     * @return  {@code true} if there are more tokens;
+     *          {@code false} otherwise.
+     * @see     java.util.Enumeration
+     * @see     java.util.StringTokenizer#hasMoreTokens()
+     */
+    public boolean hasMoreElements() {
+        return hasMoreTokens();
+    }
+
+    /**
+     * Returns the same value as the {@code nextToken} method,
+     * except that its declared return value is {@code Object} rather than
+     * {@code String}. It exists so that this class can implement the
+     * {@code Enumeration} interface.
+     *
+     * @return     the next token in the string.
+     * @throws     NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @see        java.util.Enumeration
+     * @see        java.util.StringTokenizer#nextToken()
+     */
+    public Object nextElement() {
+        return nextToken();
+    }
+
+    /**
+     * Calculates the number of times that this tokenizer's
+     * {@code nextToken} method can be called before it generates an
+     * exception. The current position is not advanced.
+     *
+     * @return  the number of tokens remaining in the string using the current
+     *          delimiter set.
+     * @see     java.util.StringTokenizer#nextToken()
+     */
+    public int countTokens() {
+        int count = 0;
+        int currpos = currentPosition;
+        while (currpos < maxPosition) {
+            currpos = skipDelimiters(currpos);
+            if (currpos >= maxPosition)
+                break;
+            currpos = scanToken(currpos);
+            count++;
+        }
+        return count;
+    }
+}
diff --git a/android-35/java/util/TimSort.java b/android-35/java/util/TimSort.java
new file mode 100644
index 0000000..7cce1cc
--- /dev/null
+++ b/android-35/java/util/TimSort.java
@@ -0,0 +1,940 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2009 Google Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A stable, adaptive, iterative mergesort that requires far fewer than
+ * n lg(n) comparisons when running on partially sorted arrays, while
+ * offering performance comparable to a traditional mergesort when run
+ * on random arrays.  Like all proper mergesorts, this sort is stable and
+ * runs O(n log n) time (worst case).  In the worst case, this sort requires
+ * temporary storage space for n/2 object references; in the best case,
+ * it requires only a small constant amount of space.
+ *
+ * This implementation was adapted from Tim Peters's list sort for
+ * Python, which is described in detail here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listsort.txt
+ *
+ * Tim's C code may be found here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listobject.c
+ *
+ * The underlying techniques are described in this paper (and may have
+ * even earlier origins):
+ *
+ *  "Optimistic Sorting and Information Theoretic Complexity"
+ *  Peter McIlroy
+ *  SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),
+ *  pp 467-474, Austin, Texas, 25-27 January 1993.
+ *
+ * While the API to this class consists solely of static methods, it is
+ * (privately) instantiable; a TimSort instance holds the state of an ongoing
+ * sort, assuming the input array is large enough to warrant the full-blown
+ * TimSort. Small arrays are sorted in place, using a binary insertion sort.
+ *
+ * @author Josh Bloch
+ */
+class TimSort<T> {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final T[] a;
+
+    /**
+     * The comparator for this sort.
+     */
+    private final Comparator<? super T> c;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private T[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the sort
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
+        this.a = a;
+        this.c = c;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), tlen);
+            tmp = newArray;
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param c the comparator to use
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
+                         T[] work, int workBase, int workLen) {
+        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
+            binarySort(a, lo, hi, lo + initRunLen, c);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi, c);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen, c);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     * @param c comparator to used for the sort
+     */
+    @SuppressWarnings("fallthrough")
+    private static <T> void binarySort(T[] a, int lo, int hi, int start,
+                                       Comparator<? super T> c) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            T pivot = a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (c.compare(pivot, a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+     *        It is required that {@code lo < hi}.
+     * @param c the comparator to used for the sort
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
+                                                    Comparator<? super T> c) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     *
+     * Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer,
+     * Richard Bubel and Reiner Hahnle, this is fixed with respect to
+     * the analysis in "On the Worst-Case Complexity of TimSort" by
+     * Nicolas Auger, Vincent Jug, Cyril Nicaud, and Carine Pivoteau.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] ||
+                n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+            } else if (n < 0 || runLen[n] > runLen[n + 1]) {
+                break; // Invariant is established
+            }
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight(a[base2], a, base1, len1, 0, c);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static <T> int gallopLeft(T key, T[] a, int base, int len, int hint,
+                                      Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+        int lastOfs = 0;
+        int ofs = 1;
+        if (c.compare(key, a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static <T> int gallopRight(T key, T[] a, int base, int len,
+                                       int hint, Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (c.compare(key, a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len1);
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (c.compare(a[cursor2], tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1) // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (c.compare(tmp[cursor2], a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)  // len2 == 1 || len2 == 0
+                        break outer;
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private T[] ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = -1 >>> Integer.numberOfLeadingZeros(minCapacity);
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), newSize);
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+}
diff --git a/android-35/java/util/TimeZone.java b/android-35/java/util/TimeZone.java
new file mode 100644
index 0000000..a1ee972
--- /dev/null
+++ b/android-35/java/util/TimeZone.java
@@ -0,0 +1,800 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import android.icu.text.TimeZoneNames;
+import com.android.i18n.timezone.ZoneInfoData;
+import com.android.i18n.timezone.ZoneInfoDb;
+import com.android.icu.util.ExtendedTimeZone;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.ZoneId;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import libcore.io.IoUtils;
+import libcore.util.ZoneInfo;
+
+import dalvik.system.RuntimeHooks;
+
+/**
+ * {@code TimeZone} represents a time zone offset, and also figures out daylight
+ * savings.
+ *
+ * <p>
+ * Typically, you get a {@code TimeZone} using {@code getDefault}
+ * which creates a {@code TimeZone} based on the time zone where the program
+ * is running. For example, for a program running in Japan, {@code getDefault}
+ * creates a {@code TimeZone} object based on Japanese Standard Time.
+ *
+ * <p>
+ * You can also get a {@code TimeZone} using {@code getTimeZone}
+ * along with a time zone ID. For instance, the time zone ID for the
+ * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
+ * U.S. Pacific Time {@code TimeZone} object with:
+ * <blockquote><pre>
+ * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ * </pre></blockquote>
+ * You can use the {@code getAvailableIDs} method to iterate through
+ * all the supported time zone IDs. You can then choose a
+ * supported ID to get a {@code TimeZone}.
+ * If the time zone you want is not represented by one of the
+ * supported IDs, then a custom time zone ID can be specified to
+ * produce a TimeZone. The syntax of a custom time zone ID is:
+ *
+ * <blockquote><pre>
+ * <a id="CustomID"><i>CustomID:</i></a>
+ *         {@code GMT} <i>Sign</i> <i>Hours</i> {@code :} <i>Minutes</i>
+ *         {@code GMT} <i>Sign</i> <i>Hours</i> <i>Minutes</i>
+ *         {@code GMT} <i>Sign</i> <i>Hours</i>
+ * <i>Sign:</i> one of
+ *         {@code + -}
+ * <i>Hours:</i>
+ *         <i>Digit</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         {@code 0 1 2 3 4 5 6 7 8 9}
+ * </pre></blockquote>
+ *
+ * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
+ * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
+ * hours and ten minutes ahead of GMT, respectively.
+ * <p>
+ * The format is locale independent and digits must be taken from the
+ * Basic Latin block of the Unicode standard. No daylight saving time
+ * transition schedule can be specified with a custom time zone ID. If
+ * the specified string doesn't match the syntax, {@code "GMT"}
+ * is used.
+ * <p>
+ * When creating a {@code TimeZone}, the specified custom time
+ * zone ID is normalized in the following syntax:
+ * <blockquote><pre>
+ * <a id="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
+ *         {@code GMT} <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
+ * <i>Sign:</i> one of
+ *         {@code + -}
+ * <i>TwoDigitHours:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         {@code 0 1 2 3 4 5 6 7 8 9}
+ * </pre></blockquote>
+ * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
+ *
+ * <h2>Three-letter time zone IDs</h2>
+ *
+ * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
+ * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
+ * use is deprecated</strong> because the same abbreviation is often used
+ * for multiple time zones (for example, "CST" could be U.S. "Central Standard
+ * Time" and "China Standard Time"), and the Java platform can then only
+ * recognize one of them.
+ *
+ *
+ * @see          Calendar
+ * @see          GregorianCalendar
+ * @see          SimpleTimeZone
+ * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since        1.1
+ */
+public abstract class TimeZone implements Serializable, Cloneable {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public TimeZone() {
+    }
+
+    /**
+     * A style specifier for {@code getDisplayName()} indicating
+     * a short name, such as "PST."
+     * @see #LONG
+     * @since 1.2
+     */
+    public static final int SHORT = 0;
+
+    /**
+     * A style specifier for {@code getDisplayName()} indicating
+     * a long name, such as "Pacific Standard Time."
+     * @see #SHORT
+     * @since 1.2
+     */
+    public static final int LONG  = 1;
+
+    // Android-changed: Use a preload holder to allow compile-time initialization of TimeZone and
+    // dependents.
+    private static class NoImagePreloadHolder {
+        public static final Pattern CUSTOM_ZONE_ID_PATTERN = Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+    }
+
+    // Proclaim serialization compatibility with JDK 1.1
+    @java.io.Serial
+    static final long serialVersionUID = 3581463369166924961L;
+
+    // Android-changed: common timezone instances.
+    private static final TimeZone GMT = new SimpleTimeZone(0, "GMT");
+    private static final TimeZone UTC = new SimpleTimeZone(0, "UTC");
+
+    /**
+     * Gets the time zone offset, for current date, modified in case of
+     * daylight savings. This is the offset to add to UTC to get local time.
+     * <p>
+     * This method returns a historically correct offset if an
+     * underlying {@code TimeZone} implementation subclass
+     * supports historical Daylight Saving Time schedule and GMT
+     * offset changes.
+     *
+     * @param era the era of the given date.
+     * @param year the year in the given date.
+     * @param month the month in the given date.
+     * Month is 0-based. e.g., 0 for January.
+     * @param day the day-in-month of the given date.
+     * @param dayOfWeek the day-of-week of the given date.
+     * @param milliseconds the milliseconds in day in <em>standard</em>
+     * local time.
+     *
+     * @return the offset in milliseconds to add to GMT to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract int getOffset(int era, int year, int month, int day,
+                                  int dayOfWeek, int milliseconds);
+
+    /**
+     * Returns the offset of this time zone from UTC at the specified
+     * date. If Daylight Saving Time is in effect at the specified
+     * date, the offset value is adjusted with the amount of daylight
+     * saving.
+     * <p>
+     * This method returns a historically correct offset value if an
+     * underlying TimeZone implementation subclass supports historical
+     * Daylight Saving Time schedule and GMT offset changes.
+     *
+     * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
+     * @return the amount of time in milliseconds to add to UTC to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        if (inDaylightTime(new Date(date))) {
+            return getRawOffset() + getDSTSavings();
+        }
+        return getRawOffset();
+    }
+
+    /**
+     * Gets the raw GMT offset and the amount of daylight saving of this
+     * time zone at the given time.
+     * @param date the milliseconds (since January 1, 1970,
+     * 00:00:00.000 GMT) at which the time zone offset and daylight
+     * saving amount are found
+     * @param offsets an array of int where the raw GMT offset
+     * (offset[0]) and daylight saving amount (offset[1]) are stored,
+     * or null if those values are not needed. The method assumes that
+     * the length of the given array is two or larger.
+     * @return the total amount of the raw GMT offset and daylight
+     * saving at the specified date.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    int getOffsets(long date, int[] offsets) {
+        int rawoffset = getRawOffset();
+        int dstoffset = 0;
+        if (inDaylightTime(new Date(date))) {
+            dstoffset = getDSTSavings();
+        }
+        if (offsets != null) {
+            offsets[0] = rawoffset;
+            offsets[1] = dstoffset;
+        }
+        return rawoffset + dstoffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * <p>
+     * If an underlying {@code TimeZone} implementation subclass
+     * supports historical GMT offset changes, the specified GMT
+     * offset is set as the latest GMT offset and the difference from
+     * the known latest GMT offset value is used to adjust all
+     * historical GMT offset values.
+     *
+     * @param offsetMillis the given base time zone offset to GMT.
+     */
+    public abstract void setRawOffset(int offsetMillis);
+
+    /**
+     * Returns the amount of time in milliseconds to add to UTC to get
+     * standard time in this time zone. Because this value is not
+     * affected by daylight saving time, it is called <I>raw
+     * offset</I>.
+     * <p>
+     * If an underlying {@code TimeZone} implementation subclass
+     * supports historical GMT offset changes, the method returns the
+     * raw offset value of the current date. In Honolulu, for example,
+     * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
+     * this method always returns -36000000 milliseconds (i.e., -10
+     * hours).
+     *
+     * @return the amount of raw offset time in milliseconds to add to UTC.
+     * @see Calendar#ZONE_OFFSET
+     */
+    public abstract int getRawOffset();
+
+    /**
+     * Gets the ID of this time zone.
+     * @return the ID of this time zone.
+     */
+    public String getID()
+    {
+        return ID;
+    }
+
+    /**
+     * Sets the time zone ID. This does not change any other data in
+     * the time zone object.
+     * @param ID the new time zone ID.
+     */
+    public void setID(String ID)
+    {
+        if (ID == null) {
+            throw new NullPointerException();
+        }
+        this.ID = ID;
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the default locale.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG},
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @return the human-readable name of this time zone in the default locale.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     */
+    public final String getDisplayName() {
+        return getDisplayName(false, LONG,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the specified {@code locale}.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG}, locale)
+     * </pre></blockquote>
+     *
+     * @param locale the locale in which to supply the display name.
+     * @return the human-readable name of this time zone in the given locale.
+     * @throws    NullPointerException if {@code locale} is {@code null}.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     */
+    public final String getDisplayName(Locale locale) {
+        return getDisplayName(false, LONG, locale);
+    }
+
+    /**
+     * Returns a name in the specified {@code style} of this {@code TimeZone}
+     * suitable for presentation to the user in the default locale. If the
+     * specified {@code daylight} is {@code true}, a Daylight Saving Time name
+     * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
+     * Time). Otherwise, a Standard Time name is returned.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(daylight, style,
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @param daylight {@code true} specifying a Daylight Saving Time name, or
+     *                 {@code false} specifying a Standard Time name
+     * @param style either {@link #LONG} or {@link #SHORT}
+     * @return the human-readable name of this time zone in the default locale.
+     * @throws    IllegalArgumentException if {@code style} is invalid.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     * @see java.text.DateFormatSymbols#getZoneStrings()
+     */
+    public final String getDisplayName(boolean daylight, int style) {
+        return getDisplayName(daylight, style,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns the {@link #SHORT short} or {@link #LONG long} name of this time
+     * zone with either standard or daylight time, as written in {@code locale}.
+     * If the name is not available, the result is in the format
+     * {@code GMT[+-]hh:mm}.
+     *
+     * @param daylightTime true for daylight time, false for standard time.
+     * @param style either {@link TimeZone#LONG} or {@link TimeZone#SHORT}.
+     * @param locale the display locale.
+     */
+    public String getDisplayName(boolean daylightTime, int style, Locale locale) {
+        // BEGIN Android-changed: implement using android.icu.text.TimeZoneNames
+        TimeZoneNames.NameType nameType;
+        switch (style) {
+            case SHORT:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                        : TimeZoneNames.NameType.SHORT_STANDARD;
+                break;
+            case LONG:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                        : TimeZoneNames.NameType.LONG_STANDARD;
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal style: " + style);
+        }
+        String canonicalID = android.icu.util.TimeZone.getCanonicalID(getID());
+        if (canonicalID != null) {
+            TimeZoneNames names = TimeZoneNames.getInstance(locale);
+            long now = System.currentTimeMillis();
+            String displayName = names.getDisplayName(canonicalID, nameType, now);
+            if (displayName != null) {
+                return displayName;
+            }
+        }
+
+        // We get here if this is a custom timezone or ICU doesn't have name data for the specific
+        // style and locale.
+        int offsetMillis = getRawOffset();
+        if (daylightTime) {
+            offsetMillis += getDSTSavings();
+        }
+        return createGmtOffsetString(true /* includeGmt */, true /* includeMinuteSeparator */,
+                offsetMillis);
+        // END Android-changed: implement using android.icu.text.TimeZoneNames
+    }
+
+    // BEGIN Android-added: utility method to format an offset as a GMT offset string.
+    /**
+     * Returns a string representation of an offset from UTC.
+     *
+     * <p>The format is "[GMT](+|-)HH[:]MM". The output is not localized.
+     *
+     * @param includeGmt true to include "GMT", false to exclude
+     * @param includeMinuteSeparator true to include the separator between hours and minutes, false
+     *     to exclude.
+     * @param offsetMillis the offset from UTC
+     *
+     * @hide used internally by SimpleDateFormat
+     */
+    public static String createGmtOffsetString(boolean includeGmt,
+            boolean includeMinuteSeparator, int offsetMillis) {
+        int offsetMinutes = offsetMillis / 60000;
+        char sign = '+';
+        if (offsetMinutes < 0) {
+            sign = '-';
+            offsetMinutes = -offsetMinutes;
+        }
+        StringBuilder builder = new StringBuilder(9);
+        if (includeGmt) {
+            builder.append("GMT");
+        }
+        builder.append(sign);
+        appendNumber(builder, 2, offsetMinutes / 60);
+        if (includeMinuteSeparator) {
+            builder.append(':');
+        }
+        appendNumber(builder, 2, offsetMinutes % 60);
+        return builder.toString();
+    }
+
+    private static void appendNumber(StringBuilder builder, int count, int value) {
+        String string = Integer.toString(value);
+        for (int i = 0; i < count - string.length(); i++) {
+            builder.append('0');
+        }
+        builder.append(string);
+    }
+    // END Android-added: utility method to format an offset as a GMT offset string.
+
+    /**
+     * Returns the amount of time to be added to local standard time
+     * to get local wall clock time.
+     *
+     * <p>The default implementation returns 3600000 milliseconds
+     * (i.e., one hour) if a call to {@link #useDaylightTime()}
+     * returns {@code true}. Otherwise, 0 (zero) is returned.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method returns the amount of saving time of the
+     * last known Daylight Saving Time rule that can be a future
+     * prediction.
+     *
+     * <p>If the amount of saving time at any given time stamp is
+     * required, construct a {@link Calendar} with this {@code
+     * TimeZone} and the time stamp, and call {@link Calendar#get(int)
+     * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
+     *
+     * @return the amount of saving time in milliseconds
+     * @since 1.4
+     * @see #inDaylightTime(Date)
+     * @see #getOffset(long)
+     * @see #getOffset(int,int,int,int,int,int)
+     * @see Calendar#ZONE_OFFSET
+     */
+    public int getDSTSavings() {
+        if (useDaylightTime()) {
+            return 3600000;
+        }
+        return 0;
+    }
+
+    /**
+     * Queries if this {@code TimeZone} uses Daylight Saving Time.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method refers to the last known Daylight Saving Time
+     * rule that can be a future prediction and may not be the same as
+     * the current rule. Consider calling {@link #observesDaylightTime()}
+     * if the current rule should also be taken into account.
+     *
+     * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
+     *         {@code false}, otherwise.
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract boolean useDaylightTime();
+
+    /**
+     * Returns {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time.
+     *
+     * <p>The default implementation returns {@code true} if
+     * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
+     * returns {@code true}.
+     *
+     * @return {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time; {@code false}
+     * otherwise.
+     * @since 1.7
+     * @see #useDaylightTime()
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public boolean observesDaylightTime() {
+        return useDaylightTime() || inDaylightTime(new Date());
+    }
+
+    /**
+     * Queries if the given {@code date} is in Daylight Saving Time in
+     * this time zone.
+     *
+     * @param date the given Date.
+     * @return {@code true} if the given date is in Daylight Saving Time,
+     *         {@code false}, otherwise.
+     */
+    public abstract boolean inDaylightTime(Date date);
+
+    /**
+     * Gets the {@code TimeZone} for the given ID.
+     *
+     * @param id the ID for a <code>TimeZone</code>, either an abbreviation
+     * such as "PST", a full name such as "America/Los_Angeles", or a custom
+     * ID such as "GMT-8:00". Note that the support of abbreviations is
+     * for JDK 1.1.x compatibility only and full names should be used.
+     *
+     * @return the specified {@code TimeZone}, or the GMT zone if the given ID
+     * cannot be understood.
+     */
+    // Android-changed: param s/ID/id; use ZoneInfoDb instead of ZoneInfo class.
+    public static synchronized TimeZone getTimeZone(String id) {
+        if (id == null) {
+            throw new NullPointerException("id == null");
+        }
+
+        // Special cases? These can clone an existing instance.
+        if (id.length() == 3) {
+            if (id.equals("GMT")) {
+                return (TimeZone) GMT.clone();
+            }
+            if (id.equals("UTC")) {
+                return (TimeZone) UTC.clone();
+            }
+        }
+
+        // In the database?
+
+        ZoneInfoData zoneInfoData = ZoneInfoDb.getInstance().makeZoneInfoData(id);
+        TimeZone zone = zoneInfoData == null ? null : ZoneInfo.createZoneInfo(zoneInfoData);
+
+        // Custom time zone?
+        if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
+            zone = getCustomTimeZone(id);
+        }
+
+        // We never return null; on failure we return the equivalent of "GMT".
+        return (zone != null) ? zone : (TimeZone) GMT.clone();
+    }
+
+    /**
+     * Gets the {@code TimeZone} for the given {@code zoneId}.
+     *
+     * @param zoneId a {@link ZoneId} from which the time zone ID is obtained
+     * @return the specified {@code TimeZone}, or the GMT zone if the given ID
+     *         cannot be understood.
+     * @throws NullPointerException if {@code zoneId} is {@code null}
+     * @since 1.8
+     */
+    public static TimeZone getTimeZone(ZoneId zoneId) {
+        String tzid = zoneId.getId(); // throws an NPE if null
+        char c = tzid.charAt(0);
+        if (c == '+' || c == '-') {
+            tzid = "GMT" + tzid;
+        } else if (c == 'Z' && tzid.length() == 1) {
+            tzid = "UTC";
+        }
+        return getTimeZone(tzid);
+    }
+
+    /**
+     * Converts this {@code TimeZone} object to a {@code ZoneId}.
+     *
+     * @return a {@code ZoneId} representing the same time zone as this
+     *         {@code TimeZone}
+     * @since 1.8
+     */
+    public ZoneId toZoneId() {
+        // Android-changed: don't support "old mapping"
+        return ZoneId.of(getID(), ZoneId.SHORT_IDS);
+    }
+
+    /**
+     * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
+     */
+    private static TimeZone getCustomTimeZone(String id) {
+        Matcher m = NoImagePreloadHolder.CUSTOM_ZONE_ID_PATTERN.matcher(id);
+        if (!m.matches()) {
+            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));
+            }
+        } 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;
+        }
+
+        String cleanId = String.format(Locale.ROOT, "GMT%c%02d:%02d", sign, hour, minute);
+
+        return new SimpleTimeZone(raw, cleanId);
+    }
+
+    /**
+     * Gets the available IDs according to the given time zone offset in milliseconds.
+     *
+     * @param rawOffset the given time zone GMT offset in milliseconds.
+     * @return an array of IDs, where the time zone for that ID has
+     * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
+     * both have GMT-07:00, but differ in daylight saving behavior.
+     * @see #getRawOffset()
+     */
+    public static synchronized String[] getAvailableIDs(int rawOffset) {
+        return ZoneInfoDb.getInstance().getAvailableIDs(rawOffset);
+    }
+
+    /**
+     * Gets all the available IDs supported.
+     * @return an array of IDs.
+     */
+    public static synchronized String[] getAvailableIDs() {
+        return ZoneInfoDb.getInstance().getAvailableIDs();
+    }
+
+    /**
+     * Gets the platform defined TimeZone ID.
+     **/
+    private static native String getSystemTimeZoneID(String javaHome,
+                                                     String country);
+
+    /**
+     * Gets the custom time zone ID based on the GMT offset of the
+     * platform. (e.g., "GMT+08:00")
+     */
+    private static native String getSystemGMTOffsetID();
+
+    /**
+     * Gets the default <code>TimeZone</code> for this host.
+     * The source of the default <code>TimeZone</code>
+     * may vary with implementation.
+     * @return a default <code>TimeZone</code>.
+     * @see #setDefault
+     */
+    public static TimeZone getDefault() {
+        return (TimeZone) getDefaultRef().clone();
+    }
+
+    /**
+     * Returns the reference to the default TimeZone object. This
+     * method doesn't create a clone.
+     */
+    static synchronized TimeZone getDefaultRef() {
+        if (defaultTimeZone == null) {
+            Supplier<String> tzGetter = RuntimeHooks.getTimeZoneIdSupplier();
+            String zoneName = (tzGetter != null) ? tzGetter.get() : null;
+            if (zoneName != null) {
+                zoneName = zoneName.trim();
+            }
+            if (zoneName == null || zoneName.isEmpty()) {
+                try {
+                    // On the host, we can find the configured timezone here.
+                    zoneName = IoUtils.readFileAsString("/etc/timezone");
+                } catch (IOException ex) {
+                    // "vogar --mode device" can end up here.
+                    // TODO: give libcore access to Android system properties and read "persist.sys.timezone".
+                    zoneName = "GMT";
+                }
+            }
+            defaultTimeZone = TimeZone.getTimeZone(zoneName);
+        }
+        return defaultTimeZone;
+    }
+
+    /**
+     * Sets the {@code TimeZone} that is returned by the {@code getDefault}
+     * method. {@code timeZone} is cached. If {@code timeZone} is null, the cached
+     * default {@code TimeZone} is cleared. This method doesn't change the value
+     * of the {@code user.timezone} property.
+     *
+     * @param timeZone the new default {@code TimeZone}, or null
+     * @see #getDefault
+     */
+    // Android-changed: s/zone/timeZone, synchronized, removed mention of SecurityException
+    public synchronized static void setDefault(TimeZone timeZone)
+    {
+        @SuppressWarnings("removal")
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission
+                    ("user.timezone", "write"));
+        }
+        defaultTimeZone = timeZone != null ? (TimeZone) timeZone.clone() : null;
+        // Android-changed: notify ICU4J of changed default TimeZone.
+        ExtendedTimeZone.clearDefaultTimeZone();
+    }
+
+    /**
+     * Returns true if this zone has the same rule and offset as another zone.
+     * That is, if this zone differs only in ID, if at all.  Returns false
+     * if the other zone is null.
+     * @param other the {@code TimeZone} object to be compared with
+     * @return true if the other zone is not null and is the same as this one,
+     * with the possible exception of the ID
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        return other != null && getRawOffset() == other.getRawOffset() &&
+            useDaylightTime() == other.useDaylightTime();
+    }
+
+    /**
+     * Creates a copy of this {@code TimeZone}.
+     *
+     * @return a clone of this {@code TimeZone}
+     */
+    public Object clone()
+    {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * The null constant as a TimeZone.
+     */
+    static final TimeZone NO_TIMEZONE = null;
+
+    // =======================privates===============================
+
+    /**
+     * The string identifier of this {@code TimeZone}.  This is a
+     * programmatic identifier used internally to look up {@code TimeZone}
+     * objects from the system table and also to map them to their localized
+     * display names.  {@code ID} values are unique in the system
+     * table but may not be for dynamically created zones.
+     * @serial
+     */
+    private String           ID;
+    private static volatile TimeZone defaultTimeZone;
+}
diff --git a/android-35/java/util/Timer.java b/android-35/java/util/Timer.java
new file mode 100644
index 0000000..6b8b708
--- /dev/null
+++ b/android-35/java/util/Timer.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.lang.ref.Cleaner.Cleanable;
+import jdk.internal.ref.CleanerFactory;
+
+/**
+ * A facility for threads to schedule tasks for future execution in a
+ * background thread.  Tasks may be scheduled for one-time execution, or for
+ * repeated execution at regular intervals.
+ *
+ * <p>Corresponding to each {@code Timer} object is a single background
+ * thread that is used to execute all of the timer's tasks, sequentially.
+ * Timer tasks should complete quickly.  If a timer task takes excessive time
+ * to complete, it "hogs" the timer's task execution thread.  This can, in
+ * turn, delay the execution of subsequent tasks, which may "bunch up" and
+ * execute in rapid succession when (and if) the offending task finally
+ * completes.
+ *
+ * <p>After the last live reference to a {@code Timer} object goes away
+ * <i>and</i> all outstanding tasks have completed execution, the timer's task
+ * execution thread terminates gracefully (and becomes subject to garbage
+ * collection).  However, this can take arbitrarily long to occur.  By
+ * default, the task execution thread does not run as a <i>daemon thread</i>,
+ * so it is capable of keeping an application from terminating.  If a caller
+ * wants to terminate a timer's task execution thread rapidly, the caller
+ * should invoke the timer's {@code cancel} method.
+ *
+ * <p>If the timer's task execution thread terminates unexpectedly, for
+ * example, because its {@code stop} method is invoked, any further
+ * attempt to schedule a task on the timer will result in an
+ * {@code IllegalStateException}, as if the timer's {@code cancel}
+ * method had been invoked.
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * {@code Timer} object without the need for external synchronization.
+ *
+ * <p>This class does <i>not</i> offer real-time guarantees: it schedules
+ * tasks using the {@code Object.wait(long)} method.
+ *
+ * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
+ * one of the concurrency utilities therein is the {@link
+ * java.util.concurrent.ScheduledThreadPoolExecutor
+ * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
+ * executing tasks at a given rate or delay.  It is effectively a more
+ * versatile replacement for the {@code Timer}/{@code TimerTask}
+ * combination, as it allows multiple service threads, accepts various
+ * time units, and doesn't require subclassing {@code TimerTask} (just
+ * implement {@code Runnable}).  Configuring {@code
+ * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
+ * {@code Timer}.
+ *
+ * <p>Implementation note: This class scales to large numbers of concurrently
+ * scheduled tasks (thousands should present no problem).  Internally,
+ * it uses a binary heap to represent its task queue, so the cost to schedule
+ * a task is O(log n), where n is the number of concurrently scheduled tasks.
+ *
+ * <p>Implementation note: All constructors start a timer thread.
+ *
+ * @author  Josh Bloch
+ * @see     TimerTask
+ * @see     Object#wait(long)
+ * @since   1.3
+ */
+
+public class Timer {
+    /**
+     * The timer task queue.  This data structure is shared with the timer
+     * thread.  The timer produces tasks, via its various schedule calls,
+     * and the timer thread consumes, executing timer tasks as appropriate,
+     * and removing them from the queue when they're obsolete.
+     */
+    // Android-added: @ReachabilitySensitive
+    // Otherwise the finalizer may cancel the Timer in the middle of a
+    // sched() call.
+    @ReachabilitySensitive
+    private final TaskQueue queue = new TaskQueue();
+
+    /**
+     * The timer thread.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final TimerThread thread = new TimerThread(queue);
+
+    /**
+     * An object of this class is registered with a Cleaner as the cleanup
+     * handler for this Timer object.  This causes the execution thread to
+     * exit gracefully when there are no live references to the Timer object
+     * and no tasks in the timer queue.
+     */
+    private static class ThreadReaper implements Runnable {
+        private final TaskQueue queue;
+        private final TimerThread thread;
+
+        ThreadReaper(TaskQueue queue, TimerThread thread) {
+            this.queue = queue;
+            this.thread = thread;
+        }
+
+        public void run() {
+            synchronized(queue) {
+                thread.newTasksMayBeScheduled = false;
+                queue.notify(); // In case queue is empty.
+            }
+        }
+    }
+
+    private final Cleanable cleanup;
+
+    /**
+     * This ID is used to generate thread names.
+     */
+    private static final AtomicInteger nextSerialNumber = new AtomicInteger();
+    private static int serialNumber() {
+        return nextSerialNumber.getAndIncrement();
+    }
+
+    /**
+     * Creates a new timer.  The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     */
+    public Timer() {
+        this("Timer-" + serialNumber());
+    }
+
+    /**
+     * Creates a new timer whose associated thread may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     * A daemon thread is called for if the timer will be used to
+     * schedule repeating "maintenance activities", which must be
+     * performed as long as the application is running, but should not
+     * prolong the lifetime of the application.
+     *
+     * @param isDaemon true if the associated thread should run as a daemon.
+     */
+    public Timer(boolean isDaemon) {
+        this("Timer-" + serialNumber(), isDaemon);
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name.
+     * The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name) {
+        this(name, false);
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name,
+     * and may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @param isDaemon true if the associated thread should run as a daemon
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name, boolean isDaemon) {
+        var threadReaper = new ThreadReaper(queue, thread);
+        this.cleanup = CleanerFactory.cleaner().register(this, threadReaper);
+        thread.setName(name);
+        thread.setDaemon(isDaemon);
+        thread.start();
+    }
+
+    /**
+     * Schedules the specified task for execution after the specified delay.
+     *
+     * @param task  task to be scheduled.
+     * @param delay delay in milliseconds before task is to be executed.
+     * @throws IllegalArgumentException if {@code delay} is negative, or
+     *         {@code delay + System.currentTimeMillis()} is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        sched(task, System.currentTimeMillis()+delay, 0);
+    }
+
+    /**
+     * Schedules the specified task for execution at the specified time.  If
+     * the time is in the past, the task is scheduled for immediate execution.
+     *
+     * @param task task to be scheduled.
+     * @param time time at which task is to be executed.
+     * @throws IllegalArgumentException if {@code time.getTime()} is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code time} is null
+     */
+    public void schedule(TimerTask task, Date time) {
+        sched(task, time.getTime(), 0);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying {@code Object.wait(long)} is accurate).
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying {@code Object.wait(long)} is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * it is scheduled for immediate execution.
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void schedule(TimerTask task, Date firstTime, long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying {@code Object.wait(long)} is accurate).
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying {@code Object.wait(long)} is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * then any "missed" executions will be scheduled for immediate "catch up"
+     * execution.
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
+                                    long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), period);
+    }
+
+    /**
+     * Schedule the specified timer task for execution at the specified
+     * time with the specified period, in milliseconds.  If period is
+     * positive, the task is scheduled for repeated execution; if period is
+     * zero, the task is scheduled for one-time execution. Time is specified
+     * in Date.getTime() format.  This method checks timer state, task state,
+     * and initial execution time, but not period.
+     *
+     * @throws IllegalArgumentException if {@code time} is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    private void sched(TimerTask task, long time, long period) {
+        if (time < 0)
+            throw new IllegalArgumentException("Illegal execution time.");
+
+        // Constrain value of period sufficiently to prevent numeric
+        // overflow while still being effectively infinitely large.
+        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
+            period >>= 1;
+
+        synchronized(queue) {
+            if (!thread.newTasksMayBeScheduled)
+                throw new IllegalStateException("Timer already cancelled.");
+
+            synchronized(task.lock) {
+                if (task.state != TimerTask.VIRGIN)
+                    throw new IllegalStateException(
+                        "Task already scheduled or cancelled");
+                task.nextExecutionTime = time;
+                task.period = period;
+                task.state = TimerTask.SCHEDULED;
+            }
+
+            queue.add(task);
+            if (queue.getMin() == task)
+                queue.notify();
+        }
+    }
+
+    /**
+     * Terminates this timer, discarding any currently scheduled tasks.
+     * Does not interfere with a currently executing task (if it exists).
+     * Once a timer has been terminated, its execution thread terminates
+     * gracefully, and no more tasks may be scheduled on it.
+     *
+     * <p>Note that calling this method from within the run method of a
+     * timer task that was invoked by this timer absolutely guarantees that
+     * the ongoing task execution is the last task execution that will ever
+     * be performed by this timer.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     */
+    public void cancel() {
+        synchronized(queue) {
+            queue.clear();
+            cleanup.clean();
+        }
+    }
+
+    /**
+     * Removes all cancelled tasks from this timer's task queue.  <i>Calling
+     * this method has no effect on the behavior of the timer</i>, but
+     * eliminates the references to the cancelled tasks from the queue.
+     * If there are no external references to these tasks, they become
+     * eligible for garbage collection.
+     *
+     * <p>Most programs will have no need to call this method.
+     * It is designed for use by the rare application that cancels a large
+     * number of tasks.  Calling this method trades time for space: the
+     * runtime of the method may be proportional to n + c log n, where n
+     * is the number of tasks in the queue and c is the number of cancelled
+     * tasks.
+     *
+     * <p>Note that it is permissible to call this method from within
+     * a task scheduled on this timer.
+     *
+     * @return the number of tasks removed from the queue.
+     * @since 1.5
+     */
+     public int purge() {
+         int result = 0;
+
+         synchronized(queue) {
+             for (int i = queue.size(); i > 0; i--) {
+                 if (queue.get(i).state == TimerTask.CANCELLED) {
+                     queue.quickRemove(i);
+                     result++;
+                 }
+             }
+
+             if (result != 0)
+                 queue.heapify();
+         }
+
+         return result;
+     }
+}
+
+/**
+ * This "helper class" implements the timer's task execution thread, which
+ * waits for tasks on the timer queue, executions them when they fire,
+ * reschedules repeating tasks, and removes cancelled tasks and spent
+ * non-repeating tasks from the queue.
+ */
+class TimerThread extends Thread {
+    /**
+     * This flag is set to false by the reaper to inform us that there
+     * are no more live references to our Timer object.  Once this flag
+     * is true and there are no more tasks in our queue, there is no
+     * work left for us to do, so we terminate gracefully.  Note that
+     * this field is protected by queue's monitor!
+     */
+    boolean newTasksMayBeScheduled = true;
+
+    /**
+     * Our Timer's queue.  We store this reference in preference to
+     * a reference to the Timer so the reference graph remains acyclic.
+     * Otherwise, the Timer would never be garbage-collected and this
+     * thread would never go away.
+     */
+    private TaskQueue queue;
+
+    TimerThread(TaskQueue queue) {
+        this.queue = queue;
+    }
+
+    public void run() {
+        try {
+            mainLoop();
+        } finally {
+            // Someone killed this Thread, behave as if Timer cancelled
+            synchronized(queue) {
+                newTasksMayBeScheduled = false;
+                queue.clear();  // Eliminate obsolete references
+            }
+        }
+    }
+
+    /**
+     * The main timer loop.  (See class comment.)
+     */
+    private void mainLoop() {
+        while (true) {
+            try {
+                TimerTask task;
+                boolean taskFired;
+                synchronized(queue) {
+                    // Wait for queue to become non-empty
+                    while (queue.isEmpty() && newTasksMayBeScheduled)
+                        queue.wait();
+                    if (queue.isEmpty())
+                        break; // Queue is empty and will forever remain; die
+
+                    // Queue nonempty; look at first evt and do the right thing
+                    long currentTime, executionTime;
+                    task = queue.getMin();
+                    synchronized(task.lock) {
+                        if (task.state == TimerTask.CANCELLED) {
+                            queue.removeMin();
+                            continue;  // No action required, poll queue again
+                        }
+                        currentTime = System.currentTimeMillis();
+                        executionTime = task.nextExecutionTime;
+                        if (taskFired = (executionTime<=currentTime)) {
+                            if (task.period == 0) { // Non-repeating, remove
+                                queue.removeMin();
+                                task.state = TimerTask.EXECUTED;
+                            } else { // Repeating task, reschedule
+                                queue.rescheduleMin(
+                                  task.period<0 ? currentTime   - task.period
+                                                : executionTime + task.period);
+                            }
+                        }
+                    }
+                    if (!taskFired) // Task hasn't yet fired; wait
+                        queue.wait(executionTime - currentTime);
+                }
+                if (taskFired)  // Task fired; run it, holding no locks
+                    task.run();
+            } catch(InterruptedException e) {
+            }
+        }
+    }
+}
+
+/**
+ * This class represents a timer task queue: a priority queue of TimerTasks,
+ * ordered on nextExecutionTime.  Each Timer object has one of these, which it
+ * shares with its TimerThread.  Internally this class uses a heap, which
+ * offers log(n) performance for the add, removeMin and rescheduleMin
+ * operations, and constant time performance for the getMin operation.
+ */
+class TaskQueue {
+    /**
+     * Priority queue represented as a balanced binary heap: the two children
+     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
+     * ordered on the nextExecutionTime field: The TimerTask with the lowest
+     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
+     * each node n in the heap, and each descendant of n, d,
+     * n.nextExecutionTime <= d.nextExecutionTime.
+     */
+    private TimerTask[] queue = new TimerTask[128];
+
+    /**
+     * The number of tasks in the priority queue.  (The tasks are stored in
+     * queue[1] up to queue[size]).
+     */
+    private int size = 0;
+
+    /**
+     * Returns the number of tasks currently on the queue.
+     */
+    int size() {
+        return size;
+    }
+
+    /**
+     * Adds a new task to the priority queue.
+     */
+    void add(TimerTask task) {
+        // Grow backing store if necessary
+        if (size + 1 == queue.length)
+            queue = Arrays.copyOf(queue, 2*queue.length);
+
+        queue[++size] = task;
+        fixUp(size);
+    }
+
+    /**
+     * Return the "head task" of the priority queue.  (The head task is an
+     * task with the lowest nextExecutionTime.)
+     */
+    TimerTask getMin() {
+        return queue[1];
+    }
+
+    /**
+     * Return the ith task in the priority queue, where i ranges from 1 (the
+     * head task, which is returned by getMin) to the number of tasks on the
+     * queue, inclusive.
+     */
+    TimerTask get(int i) {
+        return queue[i];
+    }
+
+    /**
+     * Remove the head task from the priority queue.
+     */
+    void removeMin() {
+        queue[1] = queue[size];
+        queue[size--] = null;  // Drop extra reference to prevent memory leak
+        fixDown(1);
+    }
+
+    /**
+     * Removes the ith element from queue without regard for maintaining
+     * the heap invariant.  Recall that queue is one-based, so
+     * 1 <= i <= size.
+     */
+    void quickRemove(int i) {
+        assert i <= size;
+
+        queue[i] = queue[size];
+        queue[size--] = null;  // Drop extra ref to prevent memory leak
+    }
+
+    /**
+     * Sets the nextExecutionTime associated with the head task to the
+     * specified value, and adjusts priority queue accordingly.
+     */
+    void rescheduleMin(long newTime) {
+        queue[1].nextExecutionTime = newTime;
+        fixDown(1);
+    }
+
+    /**
+     * Returns true if the priority queue contains no elements.
+     */
+    boolean isEmpty() {
+        return size==0;
+    }
+
+    /**
+     * Removes all elements from the priority queue.
+     */
+    void clear() {
+        // Null out task references to prevent memory leak
+        for (int i=1; i<=size; i++)
+            queue[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) assuming the heap
+     * satisfies the invariant except possibly for the leaf-node indexed by k
+     * (which may have a nextExecutionTime less than its parent's).
+     *
+     * This method functions by "promoting" queue[k] up the hierarchy
+     * (by swapping it with its parent) repeatedly until queue[k]'s
+     * nextExecutionTime is greater than or equal to that of its parent.
+     */
+    private void fixUp(int k) {
+        while (k > 1) {
+            int j = k >> 1;
+            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the subtree
+     * rooted at k, which is assumed to satisfy the heap invariant except
+     * possibly for node k itself (which may have a nextExecutionTime greater
+     * than its children's).
+     *
+     * This method functions by "demoting" queue[k] down the hierarchy
+     * (by swapping it with its smaller child) repeatedly until queue[k]'s
+     * nextExecutionTime is less than or equal to those of its children.
+     */
+    private void fixDown(int k) {
+        int j;
+        while ((j = k << 1) <= size && j > 0) {
+            if (j < size &&
+                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
+                j++; // j indexes smallest kid
+            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    void heapify() {
+        for (int i = size/2; i >= 1; i--)
+            fixDown(i);
+    }
+}
diff --git a/android-35/java/util/TimerTask.java b/android-35/java/util/TimerTask.java
new file mode 100644
index 0000000..6703cc0
--- /dev/null
+++ b/android-35/java/util/TimerTask.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A task that can be scheduled for one-time or repeated execution by a
+ * {@link Timer}.
+ *
+ * <p>A timer task is <em>not</em> reusable.  Once a task has been scheduled
+ * for execution on a {@code Timer} or cancelled, subsequent attempts to
+ * schedule it for execution will throw {@code IllegalStateException}.
+ *
+ * @author  Josh Bloch
+ * @since   1.3
+ */
+
+public abstract class TimerTask implements Runnable {
+    /**
+     * This object is used to control access to the TimerTask internals.
+     */
+    final Object lock = new Object();
+
+    /**
+     * The state of this task, chosen from the constants below.
+     */
+    int state = VIRGIN;
+
+    /**
+     * This task has not yet been scheduled.
+     */
+    static final int VIRGIN = 0;
+
+    /**
+     * This task is scheduled for execution.  If it is a non-repeating task,
+     * it has not yet been executed.
+     */
+    static final int SCHEDULED   = 1;
+
+    /**
+     * This non-repeating task has already executed (or is currently
+     * executing) and has not been cancelled.
+     */
+    static final int EXECUTED    = 2;
+
+    /**
+     * This task has been cancelled (with a call to TimerTask.cancel).
+     */
+    static final int CANCELLED   = 3;
+
+    /**
+     * Next execution time for this task in the format returned by
+     * System.currentTimeMillis, assuming this task is scheduled for execution.
+     * For repeating tasks, this field is updated prior to each task execution.
+     */
+    long nextExecutionTime;
+
+    /**
+     * Period in milliseconds for repeating tasks.  A positive value indicates
+     * fixed-rate execution.  A negative value indicates fixed-delay execution.
+     * A value of 0 indicates a non-repeating task.
+     */
+    long period = 0;
+
+    /**
+     * Creates a new timer task.
+     */
+    protected TimerTask() {
+    }
+
+    /**
+     * The action to be performed by this timer task.
+     */
+    public abstract void run();
+
+    /**
+     * Cancels this timer task.  If the task has been scheduled for one-time
+     * execution and has not yet run, or has not yet been scheduled, it will
+     * never run.  If the task has been scheduled for repeated execution, it
+     * will never run again.  (If the task is running when this call occurs,
+     * the task will run to completion, but will never run again.)
+     *
+     * <p>Note that calling this method from within the {@code run} method of
+     * a repeating timer task absolutely guarantees that the timer task will
+     * not run again.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     *
+     * @return true if this task is scheduled for one-time execution and has
+     *         not yet run, or this task is scheduled for repeated execution.
+     *         Returns false if the task was scheduled for one-time execution
+     *         and has already run, or if the task was never scheduled, or if
+     *         the task was already cancelled.  (Loosely speaking, this method
+     *         returns {@code true} if it prevents one or more scheduled
+     *         executions from taking place.)
+     */
+    public boolean cancel() {
+        synchronized(lock) {
+            boolean result = (state == SCHEDULED);
+            state = CANCELLED;
+            return result;
+        }
+    }
+
+    /**
+     * Returns the <i>scheduled</i> execution time of the most recent
+     * <i>actual</i> execution of this task.  (If this method is invoked
+     * while task execution is in progress, the return value is the scheduled
+     * execution time of the ongoing task execution.)
+     *
+     * <p>This method is typically invoked from within a task's run method, to
+     * determine whether the current execution of the task is sufficiently
+     * timely to warrant performing the scheduled activity:
+     * <pre>{@code
+     *   public void run() {
+     *       if (System.currentTimeMillis() - scheduledExecutionTime() >=
+     *           MAX_TARDINESS)
+     *               return;  // Too late; skip this execution.
+     *       // Perform the task
+     *   }
+     * }</pre>
+     * This method is typically <i>not</i> used in conjunction with
+     * <i>fixed-delay execution</i> repeating tasks, as their scheduled
+     * execution times are allowed to drift over time, and so are not terribly
+     * significant.
+     *
+     * @return the time at which the most recent execution of this task was
+     *         scheduled to occur, in the format returned by Date.getTime().
+     *         The return value is undefined if the task has yet to commence
+     *         its first execution.
+     * @see Date#getTime()
+     */
+    public long scheduledExecutionTime() {
+        synchronized(lock) {
+            return (period < 0 ? nextExecutionTime + period
+                               : nextExecutionTime - period);
+        }
+    }
+}
diff --git a/android-35/java/util/TooManyListenersException.java b/android-35/java/util/TooManyListenersException.java
new file mode 100644
index 0000000..d3fd668
--- /dev/null
+++ b/android-35/java/util/TooManyListenersException.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The {@code  TooManyListenersException } Exception is used as part of
+ * the Java Event model to annotate and implement a unicast special case of
+ * a multicast Event Source.
+ * </p>
+ * <p>
+ * The presence of a "throws TooManyListenersException" clause on any given
+ * concrete implementation of the normally multicast "void addXyzEventListener"
+ * event listener registration pattern is used to annotate that interface as
+ * implementing a unicast Listener special case, that is, that one and only
+ * one Listener may be registered on the particular event listener source
+ * concurrently.
+ * </p>
+ *
+ * @see java.util.EventObject
+ * @see java.util.EventListener
+ *
+ * @author Laurence P. G. Cable
+ * @since  1.1
+ */
+
+public class TooManyListenersException extends Exception {
+    @java.io.Serial
+    private static final long serialVersionUID = 5074640544770687831L;
+
+    /**
+     * Constructs a TooManyListenersException with no detail message.
+     * A detail message is a String that describes this particular exception.
+     */
+
+    public TooManyListenersException() {
+        super();
+    }
+
+    /**
+     * Constructs a TooManyListenersException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     */
+
+    public TooManyListenersException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/TreeMap.java b/android-35/java/util/TreeMap.java
new file mode 100644
index 0000000..74cba6b
--- /dev/null
+++ b/android-35/java/util/TreeMap.java
@@ -0,0 +1,3402 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A Red-Black tree based {@link NavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and {@code remove}
+ * operations.  Algorithms are adaptations of those in Cormen, Leiserson, and
+ * Rivest's <em>Introduction to Algorithms</em>.
+ *
+ * <p>Note that the ordering maintained by a tree map, like any sorted map, and
+ * whether or not an explicit comparator is provided, must be <em>consistent
+ * with {@code equals}</em> if this sorted map is to correctly implement the
+ * {@code Map} interface.  (See {@code Comparable} or {@code Comparator} for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its {@code
+ * compareTo} (or {@code compare}) method, so two keys that are deemed equal by
+ * this method are, from the standpoint of the sorted map, equal.  The behavior
+ * of a sorted map <em>is</em> well-defined even if its ordering is
+ * inconsistent with {@code equals}; it just fails to obey the general contract
+ * of the {@code Map} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a map concurrently, and at least one of the
+ * threads modifies the map structurally, it <em>must</em> be synchronized
+ * externally.  (A structural modification is any operation that adds or
+ * deletes one or more mappings; merely changing the value associated
+ * with an existing key is not a structural modification.)  This is
+ * typically accomplished by synchronizing on some object that naturally
+ * encapsulates the map.
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map: <pre>
+ *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</pre>
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <em>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</em>
+ *
+ * <p>The methods
+ * {@link #ceilingEntry},
+ * {@link #firstEntry},
+ * {@link #floorEntry},
+ * {@link #higherEntry},
+ * {@link #lastEntry},
+ * {@link #lowerEntry},
+ * {@link #pollFirstEntry}, and
+ * {@link #pollLastEntry}
+ * return {@link Map.Entry} instances that represent snapshots of mappings as
+ * of the time of the call. They do <em>not</em> support mutation of the
+ * underlying map via the optional {@link Map.Entry#setValue setValue} method.
+ *
+ * <p>The {@link #putFirst putFirst} and {@link #putLast putLast} methods of this class
+ * throw {@code UnsupportedOperationException}. The encounter order of mappings is determined
+ * by the comparison method; therefore, explicit positioning is not supported.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @see Map
+ * @see HashMap
+ * @see Hashtable
+ * @see Comparable
+ * @see Comparator
+ * @see Collection
+ * @since 1.2
+ */
+
+public class TreeMap<K,V>
+    extends AbstractMap<K,V>
+    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
+{
+    /**
+     * The comparator used to maintain order in this tree map, or
+     * null if it uses the natural ordering of its keys.
+     *
+     * @serial
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    private final Comparator<? super K> comparator;
+
+    private transient TreeMapEntry<K,V> root;
+
+    /**
+     * The number of entries in the tree
+     */
+    private transient int size = 0;
+
+    /**
+     * The number of structural modifications to the tree.
+     */
+    private transient int modCount = 0;
+
+    /**
+     * Constructs a new, empty tree map, using the natural ordering of its
+     * keys.  All keys inserted into the map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  If the user attempts to put a key into the
+     * map that violates this constraint (for example, the user attempts to
+     * put a string key into a map whose keys are integers), the
+     * {@code put(Object key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeMap() {
+        comparator = null;
+    }
+
+    /**
+     * Constructs a new, empty tree map, ordered according to the given
+     * comparator.  All keys inserted into the map must be <em>mutually
+     * comparable</em> by the given comparator: {@code comparator.compare(k1,
+     * k2)} must not throw a {@code ClassCastException} for any keys
+     * {@code k1} and {@code k2} in the map.  If the user attempts to put
+     * a key into the map that violates this constraint, the {@code put(Object
+     * key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public TreeMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings as the given
+     * map, ordered according to the <em>natural ordering</em> of its keys.
+     * All keys inserted into the new map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  This method runs in n*log(n) time.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in m are not {@link Comparable},
+     *         or are not mutually comparable
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(Map<? extends K, ? extends V> m) {
+        comparator = null;
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings and
+     * using the same ordering as the specified sorted map.  This
+     * method runs in linear time.
+     *
+     * @param  m the sorted map whose mappings are to be placed in this map,
+     *         and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(SortedMap<K, ? extends V> m) {
+        comparator = m.comparator();
+        try {
+            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
+        } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the
+     *         specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such
+     * that {@code (value==null ? v==null : value.equals(v))}.  This
+     * operation will probably require time linear in the map size for
+     * most implementations.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e))
+            if (valEquals(value, e.value))
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <em>necessarily</em>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V get(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        return (p==null ? null : p.value);
+    }
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        return key(getFirstEntry());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        return key(getLastEntry());
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+     public V putFirst(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public V putLast(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param  map mappings to be stored in this map
+     * @throws ClassCastException if the class of a key or value in
+     *         the specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null or
+     *         the specified map contains a null key and this map does not
+     *         permit null keys
+     */
+    public void putAll(Map<? extends K, ? extends V> map) {
+        int mapSize = map.size();
+        if (size==0 && mapSize!=0 && map instanceof SortedMap) {
+            if (Objects.equals(comparator, ((SortedMap<?,?>)map).comparator())) {
+                ++modCount;
+                try {
+                    buildFromSorted(mapSize, map.entrySet().iterator(),
+                                    null, null);
+                } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
+                }
+                return;
+            }
+        }
+        super.putAll(map);
+    }
+
+    /**
+     * Returns this map's entry for the given key, or {@code null} if the map
+     * does not contain an entry for the key.
+     *
+     * @return this map's entry for the given key, or {@code null} if the map
+     *         does not contain an entry for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    final TreeMapEntry<K,V> getEntry(Object key) {
+        // Offload comparator-based version for sake of performance
+        if (comparator != null)
+            return getEntryUsingComparator(key);
+        Objects.requireNonNull(key);
+        @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = k.compareTo(p.key);
+            if (cmp < 0)
+                p = p.left;
+            else if (cmp > 0)
+                p = p.right;
+            else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Version of getEntry using comparator. Split off from getEntry
+     * for performance. (This is not worth doing for most methods,
+     * that are less dependent on comparator performance, but is
+     * worthwhile here.)
+     */
+    final TreeMapEntry<K,V> getEntryUsingComparator(Object key) {
+        @SuppressWarnings("unchecked")
+            K k = (K) key;
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            TreeMapEntry<K,V> p = root;
+            while (p != null) {
+                int cmp = cpr.compare(k, p.key);
+                if (cmp < 0)
+                    p = p.left;
+                else if (cmp > 0)
+                    p = p.right;
+                else
+                    return p;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the least key greater than the specified
+     * key; if no such entry exists (i.e., the greatest key in the Tree is less
+     * than the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getCeilingEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else if (cmp > 0) {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the greatest key less than the specified
+     * key; if no such entry exists (i.e., the least key in the Tree is greater
+     * than the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getFloorEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else if (cmp < 0) {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+
+        }
+        return null;
+    }
+
+    /**
+     * Returns the entry for the least key greater than the specified key; if
+     * no such entry exists (i.e., the greatest key in the Tree is less than
+     * or equal to the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getHigherEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the entry for the greatest key less than the specified key; if
+     * no such entry exists (i.e., the least key in the Tree is greater than
+     * or equal to the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getLowerEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     *
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V put(K key, V value) {
+        return put(key, value, true);
+    }
+
+    @Override
+    public V putIfAbsent(K key, V value) {
+        return put(key, value, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * mapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * mapping function modified this map
+     */
+    @Override
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V newValue;
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            newValue = callMappingFunctionWithCheck(key, mappingFunction);
+            if (newValue != null) {
+                addEntryToEmptyMap(key, newValue);
+                return newValue;
+            } else {
+                return null;
+            }
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else {
+                    if (t.value == null) {
+                        t.value = callMappingFunctionWithCheck(key, mappingFunction);
+                    }
+                    return t.value;
+                }
+            } while (t != null);
+        } else {
+            Objects.requireNonNull(key);
+            @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else {
+                    if (t.value == null) {
+                        t.value = callMappingFunctionWithCheck(key, mappingFunction);
+                    }
+                    return t.value;
+                }
+            } while (t != null);
+        }
+        newValue = callMappingFunctionWithCheck(key, mappingFunction);
+        if (newValue != null) {
+            addEntry(key, newValue, parent, cmp < 0);
+            return newValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        TreeMapEntry<K,V> oldEntry = getEntry(key);
+        if (oldEntry != null && oldEntry.value != null) {
+            return remapValue(oldEntry, key, remappingFunction);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V newValue;
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            newValue = callRemappingFunctionWithCheck(key, null, remappingFunction);
+            if (newValue != null) {
+                addEntryToEmptyMap(key, newValue);
+                return newValue;
+            } else {
+                return null;
+            }
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return remapValue(t, key, remappingFunction);
+            } while (t != null);
+        } else {
+            Objects.requireNonNull(key);
+            @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return remapValue(t, key, remappingFunction);
+            } while (t != null);
+        }
+        newValue = callRemappingFunctionWithCheck(key, null, remappingFunction);
+        if (newValue != null) {
+            addEntry(key, newValue, parent, cmp < 0);
+            return newValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method will, on a best-effort basis, throw a
+     * {@link ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation.
+     *
+     * @throws ConcurrentModificationException if it is detected that the
+     * remapping function modified this map
+     */
+    @Override
+    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            addEntryToEmptyMap(key, value);
+            return value;
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else return mergeValue(t, value, remappingFunction);
+            } while (t != null);
+        } else {
+            Objects.requireNonNull(key);
+            @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else return mergeValue(t, value, remappingFunction);
+            } while (t != null);
+        }
+        addEntry(key, value, parent, cmp < 0);
+        return value;
+    }
+
+    private V callMappingFunctionWithCheck(K key, Function<? super K, ? extends V> mappingFunction) {
+        int mc = modCount;
+        V newValue = mappingFunction.apply(key);
+        if (mc != modCount) {
+            throw new ConcurrentModificationException();
+        }
+        return newValue;
+    }
+
+    private V callRemappingFunctionWithCheck(K key, V oldValue, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        int mc = modCount;
+        V newValue = remappingFunction.apply(key, oldValue);
+        if (mc != modCount) {
+            throw new ConcurrentModificationException();
+        }
+        return newValue;
+    }
+
+    private void addEntry(K key, V value, TreeMapEntry<K, V> parent, boolean addToLeft) {
+        TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
+        if (addToLeft)
+            parent.left = e;
+        else
+            parent.right = e;
+        fixAfterInsertion(e);
+        size++;
+        modCount++;
+    }
+
+    private void addEntryToEmptyMap(K key, V value) {
+        compare(key, key); // type (and possibly null) check
+        root = new TreeMapEntry<>(key, value, null);
+        size = 1;
+        modCount++;
+    }
+
+    private V put(K key, V value, boolean replaceOld) {
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            addEntryToEmptyMap(key, value);
+            return null;
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else {
+                    V oldValue = t.value;
+                    if (replaceOld || oldValue == null) {
+                        t.value = value;
+                    }
+                    return oldValue;
+                }
+            } while (t != null);
+        } else {
+            Objects.requireNonNull(key);
+            @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else {
+                    V oldValue = t.value;
+                    if (replaceOld || oldValue == null) {
+                        t.value = value;
+                    }
+                    return oldValue;
+                }
+            } while (t != null);
+        }
+        addEntry(key, value, parent, cmp < 0);
+        return null;
+    }
+
+    private V remapValue(TreeMapEntry<K,V> t, K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        V newValue = callRemappingFunctionWithCheck(key, t.value, remappingFunction);
+        if (newValue == null) {
+            deleteEntry(t);
+            return null;
+        } else {
+            // replace old mapping
+            t.value = newValue;
+            return newValue;
+        }
+    }
+
+    private V mergeValue(TreeMapEntry<K,V> t, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        V oldValue = t.value;
+        V newValue;
+        if (t.value == null) {
+            newValue = value;
+        } else {
+            int mc = modCount;
+            newValue = remappingFunction.apply(oldValue, value);
+            if (mc != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+        if (newValue == null) {
+            deleteEntry(t);
+            return null;
+        } else {
+            // replace old mapping
+            t.value = newValue;
+            return newValue;
+        }
+    }
+
+    /**
+     * Removes the mapping for this key from this TreeMap if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V remove(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p == null)
+            return null;
+
+        V oldValue = p.value;
+        deleteEntry(p);
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        size = 0;
+        root = null;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeMap} instance. (The keys and
+     * values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        TreeMap<?,?> clone;
+        try {
+            clone = (TreeMap<?,?>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        // Put clone into "virgin" state (except for comparator)
+        clone.root = null;
+        clone.size = 0;
+        clone.modCount = 0;
+        clone.entrySet = null;
+        clone.navigableKeySet = null;
+        clone.descendingMap = null;
+
+        // Initialize clone with our mappings
+        try {
+            clone.buildFromSorted(size, entrySet().iterator(), null, null);
+        } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
+        }
+
+        return clone;
+    }
+
+    // NavigableMap API methods
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> firstEntry() {
+        return exportEntry(getFirstEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lastEntry() {
+        return exportEntry(getLastEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        TreeMapEntry<K,V> p = getFirstEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        TreeMapEntry<K,V> p = getLastEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return exportEntry(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K lowerKey(K key) {
+        return keyOrNull(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return exportEntry(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K floorKey(K key) {
+        return keyOrNull(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return exportEntry(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K ceilingKey(K key) {
+        return keyOrNull(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return exportEntry(getHigherEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K higherKey(K key) {
+        return keyOrNull(getHigherEntry(key));
+    }
+
+    // Views
+
+    /**
+     * Fields initialized to contain an instance of the entry set view
+     * the first time this view is requested.  Views are stateless, so
+     * there's no reason to create more than one.
+     */
+    private transient EntrySet entrySet;
+    private transient KeySet<K> navigableKeySet;
+    private transient NavigableMap<K,V> descendingMap;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED}
+     * and {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     */
+    public Set<K> keySet() {
+        return navigableKeySet();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K> nks = navigableKeySet;
+        return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     *
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collection's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#ORDERED}
+     * with an encounter order that is ascending order of the corresponding
+     * keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order. The
+     * set's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending key
+     * order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableMap<K, V> descendingMap() {
+        NavigableMap<K, V> km = descendingMap;
+        return (km != null) ? km :
+            (descendingMap = new DescendingSubMap<>(this,
+                                                    true, null, true,
+                                                    true, null, true));
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                    K toKey,   boolean toInclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, fromInclusive,
+                                     false, toKey,   toInclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     true,  null,  true,
+                                     false, toKey, inclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, inclusive,
+                                     true,  null,    true);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null && Objects.equals(oldValue, p.value)) {
+            p.value = newValue;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null) {
+            V oldValue = p.value;
+            p.value = value;
+            return oldValue;
+        }
+        return null;
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            action.accept(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            e.value = function.apply(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // View class support
+
+    class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator(getFirstEntry());
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return TreeMap.this.containsValue(o);
+        }
+
+        public boolean remove(Object o) {
+            for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e)) {
+                if (valEquals(e.getValue(), o)) {
+                    deleteEntry(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator(getFirstEntry());
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> entry))
+                return false;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            return p != null && valEquals(p.getValue(), value);
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> entry))
+                return false;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            if (p != null && valEquals(p.getValue(), value)) {
+                deleteEntry(p);
+                return true;
+            }
+            return false;
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    /*
+     * Unlike Values and EntrySet, the KeySet class is static,
+     * delegating to a NavigableMap to allow use by SubMaps, which
+     * outweighs the ugliness of needing type-tests for the following
+     * Iterator methods that are defined appropriately in main versus
+     * submap classes.
+     */
+
+    Iterator<K> keyIterator() {
+        return new KeyIterator(getFirstEntry());
+    }
+
+    Iterator<K> descendingKeyIterator() {
+        return new DescendingKeyIterator(getLastEntry());
+    }
+
+    static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
+        private final NavigableMap<E, ?> m;
+        KeySet(NavigableMap<E,?> map) { m = map; }
+
+        public Iterator<E> iterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).keyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
+        }
+
+        public Iterator<E> descendingIterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).descendingKeyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).descendingKeyIterator();
+        }
+
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public void clear() { m.clear(); }
+        public E lower(E e) { return m.lowerKey(e); }
+        public E floor(E e) { return m.floorKey(e); }
+        public E ceiling(E e) { return m.ceilingKey(e); }
+        public E higher(E e) { return m.higherKey(e); }
+        public E first() { return m.firstKey(); }
+        public E last() { return m.lastKey(); }
+        public Comparator<? super E> comparator() { return m.comparator(); }
+        public E pollFirst() {
+            Map.Entry<E,?> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public E pollLast() {
+            Map.Entry<E,?> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public boolean remove(Object o) {
+            int oldSize = size();
+            m.remove(o);
+            return size() != oldSize;
+        }
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                      E toElement,   boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                          toElement,   toInclusive));
+        }
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return headSet(toElement, false);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<E> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<E> spliterator() {
+            return keySpliteratorFor(m);
+        }
+    }
+
+    /**
+     * Base class for TreeMap Iterators
+     */
+    abstract class PrivateEntryIterator<T> implements Iterator<T> {
+        TreeMapEntry<K,V> next;
+        TreeMapEntry<K,V> lastReturned;
+        int expectedModCount;
+
+        PrivateEntryIterator(TreeMapEntry<K,V> first) {
+            expectedModCount = modCount;
+            lastReturned = null;
+            next = first;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final TreeMapEntry<K,V> nextEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = successor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        final TreeMapEntry<K,V> prevEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = predecessor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            // deleted entries are replaced by their successors
+            if (lastReturned.left != null && lastReturned.right != null)
+                next = lastReturned;
+            deleteEntry(lastReturned);
+            expectedModCount = modCount;
+            lastReturned = null;
+        }
+    }
+
+    final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
+        EntryIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    final class ValueIterator extends PrivateEntryIterator<V> {
+        ValueIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    final class KeyIterator extends PrivateEntryIterator<K> {
+        KeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return nextEntry().key;
+        }
+    }
+
+    final class DescendingKeyIterator extends PrivateEntryIterator<K> {
+        DescendingKeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return prevEntry().key;
+        }
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            deleteEntry(lastReturned);
+            lastReturned = null;
+            expectedModCount = modCount;
+        }
+    }
+
+    // Little utilities
+
+    /**
+     * Compares two keys using the correct comparison method for this TreeMap.
+     */
+    @SuppressWarnings("unchecked")
+    final int compare(Object k1, Object k2) {
+        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
+            : comparator.compare((K)k1, (K)k2);
+    }
+
+    /**
+     * Test two values for equality.  Differs from o1.equals(o2) only in
+     * that it copes with {@code null} o1 properly.
+     */
+    static final boolean valEquals(Object o1, Object o2) {
+        return (o1==null ? o2==null : o1.equals(o2));
+    }
+
+    /**
+     * Return SimpleImmutableEntry for entry, or null if null
+     */
+    static <K,V> Map.Entry<K,V> exportEntry(TreeMapEntry<K,V> e) {
+        return (e == null) ? null :
+            new AbstractMap.SimpleImmutableEntry<>(e);
+    }
+
+    /**
+     * Return key for entry, or null if null
+     */
+    static <K,V> K keyOrNull(TreeMapEntry<K,V> e) {
+        return (e == null) ? null : e.key;
+    }
+
+    /**
+     * Returns the key corresponding to the specified Entry.
+     * @throws NoSuchElementException if the Entry is null
+     */
+    static <K> K key(TreeMapEntry<K,?> e) {
+        if (e==null)
+            throw new NoSuchElementException();
+        return e.key;
+    }
+
+
+    // SubMaps
+
+    /**
+     * Dummy value serving as unmatchable fence key for unbounded
+     * SubMapIterators
+     */
+    private static final Object UNBOUNDED = new Object();
+
+    /**
+     * @serial include
+     */
+    abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
+        implements NavigableMap<K,V>, java.io.Serializable {
+        // Android-changed: Explicitly add a serialVersionUID so that we're serialization.
+        // compatible with the Java-7 version of this class. Several new methods were added
+        // in Java-8 but none of them have any bearing on the serialized format of the class
+        // or require any additional state to be preserved.
+        @java.io.Serial
+        private static final long serialVersionUID = 2765629423043303731L;
+
+        /**
+         * The backing map.
+         */
+        final TreeMap<K,V> m;
+
+        /**
+         * Endpoints are represented as triples (fromStart, lo,
+         * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
+         * true, then the low (absolute) bound is the start of the
+         * backing map, and the other values are ignored. Otherwise,
+         * if loInclusive is true, lo is the inclusive bound, else lo
+         * is the exclusive bound. Similarly for the upper bound.
+         */
+        @SuppressWarnings("serial") // Conditionally serializable
+        final K lo;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final K hi;
+        final boolean fromStart, toEnd;
+        final boolean loInclusive, hiInclusive;
+
+        NavigableSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            if (!fromStart && !toEnd) {
+                if (m.compare(lo, hi) > 0)
+                    throw new IllegalArgumentException("fromKey > toKey");
+            } else {
+                if (!fromStart) // type check
+                    m.compare(lo, lo);
+                if (!toEnd)
+                    m.compare(hi, hi);
+            }
+
+            this.m = m;
+            this.fromStart = fromStart;
+            this.lo = lo;
+            this.loInclusive = loInclusive;
+            this.toEnd = toEnd;
+            this.hi = hi;
+            this.hiInclusive = hiInclusive;
+        }
+
+        // internal utilities
+
+        final boolean tooLow(Object key) {
+            if (!fromStart) {
+                int c = m.compare(key, lo);
+                if (c < 0 || (c == 0 && !loInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean tooHigh(Object key) {
+            if (!toEnd) {
+                int c = m.compare(key, hi);
+                if (c > 0 || (c == 0 && !hiInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean inRange(Object key) {
+            return !tooLow(key) && !tooHigh(key);
+        }
+
+        final boolean inClosedRange(Object key) {
+            return (fromStart || m.compare(key, lo) >= 0)
+                && (toEnd || m.compare(hi, key) >= 0);
+        }
+
+        final boolean inRange(Object key, boolean inclusive) {
+            return inclusive ? inRange(key) : inClosedRange(key);
+        }
+
+        /*
+         * Absolute versions of relation operations.
+         * Subclasses map to these using like-named "sub"
+         * versions that invert senses for descending maps
+         */
+
+        final TreeMapEntry<K,V> absLowest() {
+            TreeMapEntry<K,V> e =
+                (fromStart ?  m.getFirstEntry() :
+                 (loInclusive ? m.getCeilingEntry(lo) :
+                                m.getHigherEntry(lo)));
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHighest() {
+            TreeMapEntry<K,V> e =
+                (toEnd ?  m.getLastEntry() :
+                 (hiInclusive ?  m.getFloorEntry(hi) :
+                                 m.getLowerEntry(hi)));
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absCeiling(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getCeilingEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHigher(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getHigherEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absFloor(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getFloorEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absLower(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getLowerEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        /** Returns the absolute high fence for ascending traversal */
+        final TreeMapEntry<K,V> absHighFence() {
+            return (toEnd ? null : (hiInclusive ?
+                                    m.getHigherEntry(hi) :
+                                    m.getCeilingEntry(hi)));
+        }
+
+        /** Return the absolute low fence for descending traversal  */
+        final TreeMapEntry<K,V> absLowFence() {
+            return (fromStart ? null : (loInclusive ?
+                                        m.getLowerEntry(lo) :
+                                        m.getFloorEntry(lo)));
+        }
+
+        // Abstract methods defined in ascending vs descending classes
+        // These relay to the appropriate absolute versions
+
+        abstract TreeMapEntry<K,V> subLowest();
+        abstract TreeMapEntry<K,V> subHighest();
+        abstract TreeMapEntry<K,V> subCeiling(K key);
+        abstract TreeMapEntry<K,V> subHigher(K key);
+        abstract TreeMapEntry<K,V> subFloor(K key);
+        abstract TreeMapEntry<K,V> subLower(K key);
+
+        /** Returns ascending iterator from the perspective of this submap */
+        abstract Iterator<K> keyIterator();
+
+        abstract Spliterator<K> keySpliterator();
+
+        /** Returns descending iterator from the perspective of this submap */
+        abstract Iterator<K> descendingKeyIterator();
+
+        // public methods
+
+        public boolean isEmpty() {
+            return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
+        }
+
+        public int size() {
+            return (fromStart && toEnd) ? m.size() : entrySet().size();
+        }
+
+        public final boolean containsKey(Object key) {
+            return inRange(key) && m.containsKey(key);
+        }
+
+        public final V put(K key, V value) {
+            if (!inRange(key))
+                throw new IllegalArgumentException("key out of range");
+            return m.put(key, value);
+        }
+
+        public V putIfAbsent(K key, V value) {
+            if (!inRange(key))
+                throw new IllegalArgumentException("key out of range");
+            return m.putIfAbsent(key, value);
+        }
+
+        public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            if (!inRange(key))
+                throw new IllegalArgumentException("key out of range");
+            return m.merge(key, value, remappingFunction);
+        }
+
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            if (!inRange(key)) {
+                // Do not throw if mapping function returns null
+                // to preserve compatibility with default computeIfAbsent implementation
+                if (mappingFunction.apply(key) == null) return null;
+                throw new IllegalArgumentException("key out of range");
+            }
+            return m.computeIfAbsent(key, mappingFunction);
+        }
+
+        public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            if (!inRange(key)) {
+                // Do not throw if remapping function returns null
+                // to preserve compatibility with default computeIfAbsent implementation
+                if (remappingFunction.apply(key, null) == null) return null;
+                throw new IllegalArgumentException("key out of range");
+            }
+            return m.compute(key, remappingFunction);
+        }
+
+        public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return !inRange(key) ? null : m.computeIfPresent(key, remappingFunction);
+        }
+
+        public final V get(Object key) {
+            return !inRange(key) ? null :  m.get(key);
+        }
+
+        public final V remove(Object key) {
+            return !inRange(key) ? null : m.remove(key);
+        }
+
+        public final Map.Entry<K,V> ceilingEntry(K key) {
+            return exportEntry(subCeiling(key));
+        }
+
+        public final K ceilingKey(K key) {
+            return keyOrNull(subCeiling(key));
+        }
+
+        public final Map.Entry<K,V> higherEntry(K key) {
+            return exportEntry(subHigher(key));
+        }
+
+        public final K higherKey(K key) {
+            return keyOrNull(subHigher(key));
+        }
+
+        public final Map.Entry<K,V> floorEntry(K key) {
+            return exportEntry(subFloor(key));
+        }
+
+        public final K floorKey(K key) {
+            return keyOrNull(subFloor(key));
+        }
+
+        public final Map.Entry<K,V> lowerEntry(K key) {
+            return exportEntry(subLower(key));
+        }
+
+        public final K lowerKey(K key) {
+            return keyOrNull(subLower(key));
+        }
+
+        public final K firstKey() {
+            return key(subLowest());
+        }
+
+        public final K lastKey() {
+            return key(subHighest());
+        }
+
+        public final Map.Entry<K,V> firstEntry() {
+            return exportEntry(subLowest());
+        }
+
+        public final Map.Entry<K,V> lastEntry() {
+            return exportEntry(subHighest());
+        }
+
+        public final Map.Entry<K,V> pollFirstEntry() {
+            TreeMapEntry<K,V> e = subLowest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        public final Map.Entry<K,V> pollLastEntry() {
+            TreeMapEntry<K,V> e = subHighest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        // Views
+        transient NavigableMap<K,V> descendingMapView;
+        transient EntrySetView entrySetView;
+        transient KeySet<K> navigableKeySetView;
+
+        public final NavigableSet<K> navigableKeySet() {
+            KeySet<K> nksv = navigableKeySetView;
+            return (nksv != null) ? nksv :
+                (navigableKeySetView = new TreeMap.KeySet<>(this));
+        }
+
+        public final Set<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        public final SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public final SortedMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public final SortedMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        // View classes
+
+        abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
+            private transient int size = -1, sizeModCount;
+
+            public int size() {
+                if (fromStart && toEnd)
+                    return m.size();
+                if (size == -1 || sizeModCount != m.modCount) {
+                    sizeModCount = m.modCount;
+                    size = 0;
+                    Iterator<?> i = iterator();
+                    while (i.hasNext()) {
+                        size++;
+                        i.next();
+                    }
+                }
+                return size;
+            }
+
+            public boolean isEmpty() {
+                TreeMapEntry<K,V> n = absLowest();
+                return n == null || tooHigh(n.key);
+            }
+
+            public boolean contains(Object o) {
+                if (!(o instanceof Entry<?, ?> entry))
+                    return false;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<?, ?> node = m.getEntry(key);
+                return node != null &&
+                    valEquals(node.getValue(), entry.getValue());
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Entry<?, ?> entry))
+                    return false;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<K,V> node = m.getEntry(key);
+                if (node!=null && valEquals(node.getValue(),
+                                            entry.getValue())) {
+                    m.deleteEntry(node);
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Iterators for SubMaps
+         */
+        abstract class SubMapIterator<T> implements Iterator<T> {
+            TreeMapEntry<K,V> lastReturned;
+            TreeMapEntry<K,V> next;
+            final Object fenceKey;
+            int expectedModCount;
+
+            SubMapIterator(TreeMapEntry<K,V> first,
+                           TreeMapEntry<K,V> fence) {
+                expectedModCount = m.modCount;
+                lastReturned = null;
+                next = first;
+                fenceKey = fence == null ? UNBOUNDED : fence.key;
+            }
+
+            public final boolean hasNext() {
+                return next != null && next.key != fenceKey;
+            }
+
+            final TreeMapEntry<K,V> nextEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = successor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final TreeMapEntry<K,V> prevEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = predecessor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final void removeAscending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                // deleted entries are replaced by their successors
+                if (lastReturned.left != null && lastReturned.right != null)
+                    next = lastReturned;
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+            final void removeDescending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+        }
+
+        final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            SubMapEntryIterator(TreeMapEntry<K,V> first,
+                                TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public Map.Entry<K,V> next() {
+                return nextEntry();
+            }
+            public void remove() {
+                removeAscending();
+            }
+        }
+
+        final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            DescendingSubMapEntryIterator(TreeMapEntry<K,V> last,
+                                          TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+
+            public Map.Entry<K,V> next() {
+                return prevEntry();
+            }
+            public void remove() {
+                removeDescending();
+            }
+        }
+
+        // Implement minimal Spliterator as KeySpliterator backup
+        final class SubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            SubMapKeyIterator(TreeMapEntry<K,V> first,
+                              TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public K next() {
+                return nextEntry().key;
+            }
+            public void remove() {
+                removeAscending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K>  getComparator() {
+                return NavigableSubMap.this.comparator();
+            }
+        }
+
+        final class DescendingSubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            DescendingSubMapKeyIterator(TreeMapEntry<K,V> last,
+                                        TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+            public K next() {
+                return prevEntry().key;
+            }
+            public void remove() {
+                removeDescending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
+        @java.io.Serial
+        private static final long serialVersionUID = 912986545866124060L;
+
+        AscendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        public Comparator<? super K> comparator() {
+            return m.comparator();
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, fromInclusive,
+                                         false, toKey,   toInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases.
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!toEnd && m.compare(toKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases.
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         fromStart, lo,    loInclusive,
+                                         false,     toKey, inclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases.
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!fromStart && m.compare(fromKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases.
+                throw new IllegalArgumentException("fromKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, inclusive,
+                                         toEnd, hi,      hiInclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new DescendingSubMap<>(m,
+                                        fromStart, lo, loInclusive,
+                                        toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        final class AscendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new SubMapEntryIterator(absLowest(), absHighFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new AscendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absLowest(); }
+        TreeMapEntry<K,V> subHighest()      { return absHighest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absCeiling(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absHigher(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absFloor(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absLower(key); }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class DescendingSubMap<K,V>  extends NavigableSubMap<K,V> {
+        @java.io.Serial
+        private static final long serialVersionUID = 912986545866120460L;
+        DescendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final Comparator<? super K> reverseComparator =
+            Collections.reverseOrder(m.comparator);
+
+        public Comparator<? super K> comparator() {
+            return reverseComparator;
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey,   toInclusive,
+                                          false, fromKey, fromInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases.
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!fromStart && m.compare(toKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases.
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey, inclusive,
+                                          toEnd, hi,    hiInclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases.
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!toEnd && m.compare(fromKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases.
+                throw new IllegalArgumentException("fromKey out of range");
+            return new DescendingSubMap<>(m,
+                                          fromStart, lo, loInclusive,
+                                          false, fromKey, inclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new AscendingSubMap<>(m,
+                                       fromStart, lo, loInclusive,
+                                       toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        final class DescendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new DescendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absHighest(); }
+        TreeMapEntry<K,V> subHighest()      { return absLowest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absFloor(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absLower(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absCeiling(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absHigher(key); }
+    }
+
+    /**
+     * This class exists solely for the sake of serialization
+     * compatibility with previous releases of TreeMap that did not
+     * support NavigableMap.  It translates an old-version SubMap into
+     * a new-version AscendingSubMap. This class is never otherwise
+     * used.
+     *
+     * @serial include
+     */
+    private class SubMap extends AbstractMap<K,V>
+        implements SortedMap<K,V>, java.io.Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = -6520786458950516097L;
+        private boolean fromStart = false, toEnd = false;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private K fromKey;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private K toKey;
+        @java.io.Serial
+        private Object readResolve() {
+            return new AscendingSubMap<>(TreeMap.this,
+                                         fromStart, fromKey, true,
+                                         toEnd, toKey, false);
+        }
+        public Set<Map.Entry<K,V>> entrySet() { throw new InternalError(); }
+        public K lastKey() { throw new InternalError(); }
+        public K firstKey() { throw new InternalError(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> headMap(K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> tailMap(K fromKey) { throw new InternalError(); }
+        public Comparator<? super K> comparator() { throw new InternalError(); }
+    }
+
+
+    // Red-black mechanics
+
+    private static final boolean RED   = false;
+    private static final boolean BLACK = true;
+
+    /**
+     * Node in the Tree.  Doubles as a means to pass key-value pairs back to
+     * user (see Map.Entry).
+     */
+    // BEGIN Android-changed: Renamed Entry -> TreeMapEntry.
+    // Code references to "TreeMap.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry.
+    // END Android-changed: Renamed Entry -> TreeMapEntry.
+    static final class TreeMapEntry<K,V> implements Map.Entry<K,V> {
+        K key;
+        V value;
+        TreeMapEntry<K,V> left;
+        TreeMapEntry<K,V> right;
+        TreeMapEntry<K,V> parent;
+        boolean color = BLACK;
+
+        /**
+         * Make a new cell with given key, value, and parent, and with
+         * {@code null} child links, and BLACK color.
+         */
+        TreeMapEntry(K key, V value, TreeMapEntry<K,V> parent) {
+            this.key = key;
+            this.value = value;
+            this.parent = parent;
+        }
+
+        /**
+         * Returns the key.
+         *
+         * @return the key
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value associated with the key.
+         *
+         * @return the value associated with the key
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value currently associated with the key with the given
+         * value.
+         *
+         * @return the value associated with the key before this method was
+         *         called
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            return o instanceof Map.Entry<?, ?> e
+                    && valEquals(key,e.getKey())
+                    && valEquals(value,e.getValue());
+        }
+
+        public int hashCode() {
+            int keyHash = (key==null ? 0 : key.hashCode());
+            int valueHash = (value==null ? 0 : value.hashCode());
+            return keyHash ^ valueHash;
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    /**
+     * Returns the first Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getFirstEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.left != null)
+                p = p.left;
+        return p;
+    }
+
+    /**
+     * Returns the last Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getLastEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.right != null)
+                p = p.right;
+        return p;
+    }
+
+    /**
+     * Returns the successor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> successor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.right != null) {
+            TreeMapEntry<K,V> p = t.right;
+            while (p.left != null)
+                p = p.left;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.right) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Returns the predecessor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> predecessor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.left != null) {
+            TreeMapEntry<K,V> p = t.left;
+            while (p.right != null)
+                p = p.right;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.left) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Balancing operations.
+     *
+     * Implementations of rebalancings during insertion and deletion are
+     * slightly different than the CLR version.  Rather than using dummy
+     * nilnodes, we use a set of accessors that deal properly with null.  They
+     * are used to avoid messiness surrounding nullness checks in the main
+     * algorithms.
+     */
+
+    private static <K,V> boolean colorOf(TreeMapEntry<K,V> p) {
+        return (p == null ? BLACK : p.color);
+    }
+
+    private static <K,V> TreeMapEntry<K,V> parentOf(TreeMapEntry<K,V> p) {
+        return (p == null ? null: p.parent);
+    }
+
+    private static <K,V> void setColor(TreeMapEntry<K,V> p, boolean c) {
+        if (p != null)
+            p.color = c;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> leftOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.left;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> rightOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.right;
+    }
+
+    /** From CLR */
+    private void rotateLeft(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> r = p.right;
+            p.right = r.left;
+            if (r.left != null)
+                r.left.parent = p;
+            r.parent = p.parent;
+            if (p.parent == null)
+                root = r;
+            else if (p.parent.left == p)
+                p.parent.left = r;
+            else
+                p.parent.right = r;
+            r.left = p;
+            p.parent = r;
+        }
+    }
+
+    /** From CLR */
+    private void rotateRight(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> l = p.left;
+            p.left = l.right;
+            if (l.right != null) l.right.parent = p;
+            l.parent = p.parent;
+            if (p.parent == null)
+                root = l;
+            else if (p.parent.right == p)
+                p.parent.right = l;
+            else p.parent.left = l;
+            l.right = p;
+            p.parent = l;
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterInsertion(TreeMapEntry<K,V> x) {
+        x.color = RED;
+
+        while (x != null && x != root && x.parent.color == RED) {
+            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
+                TreeMapEntry<K,V> y = rightOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == rightOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateLeft(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateRight(parentOf(parentOf(x)));
+                }
+            } else {
+                TreeMapEntry<K,V> y = leftOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == leftOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateRight(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateLeft(parentOf(parentOf(x)));
+                }
+            }
+        }
+        root.color = BLACK;
+    }
+
+    /**
+     * Delete node p, and then rebalance the tree.
+     */
+    private void deleteEntry(TreeMapEntry<K,V> p) {
+        modCount++;
+        size--;
+
+        // If strictly internal, copy successor's element to p and then make p
+        // point to successor.
+        if (p.left != null && p.right != null) {
+            TreeMapEntry<K,V> s = successor(p);
+            p.key = s.key;
+            p.value = s.value;
+            p = s;
+        } // p has 2 children
+
+        // Start fixup at replacement node, if it exists.
+        TreeMapEntry<K,V> replacement = (p.left != null ? p.left : p.right);
+
+        if (replacement != null) {
+            // Link replacement to parent
+            replacement.parent = p.parent;
+            if (p.parent == null)
+                root = replacement;
+            else if (p == p.parent.left)
+                p.parent.left  = replacement;
+            else
+                p.parent.right = replacement;
+
+            // Null out links so they are OK to use by fixAfterDeletion.
+            p.left = p.right = p.parent = null;
+
+            // Fix replacement
+            if (p.color == BLACK)
+                fixAfterDeletion(replacement);
+        } else if (p.parent == null) { // return if we are the only node.
+            root = null;
+        } else { //  No children. Use self as phantom replacement and unlink.
+            if (p.color == BLACK)
+                fixAfterDeletion(p);
+
+            if (p.parent != null) {
+                if (p == p.parent.left)
+                    p.parent.left = null;
+                else if (p == p.parent.right)
+                    p.parent.right = null;
+                p.parent = null;
+            }
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterDeletion(TreeMapEntry<K,V> x) {
+        while (x != root && colorOf(x) == BLACK) {
+            if (x == leftOf(parentOf(x))) {
+                TreeMapEntry<K,V> sib = rightOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateLeft(parentOf(x));
+                    sib = rightOf(parentOf(x));
+                }
+
+                if (colorOf(leftOf(sib))  == BLACK &&
+                    colorOf(rightOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(rightOf(sib)) == BLACK) {
+                        setColor(leftOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateRight(sib);
+                        sib = rightOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(rightOf(sib), BLACK);
+                    rotateLeft(parentOf(x));
+                    x = root;
+                }
+            } else { // symmetric
+                TreeMapEntry<K,V> sib = leftOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateRight(parentOf(x));
+                    sib = leftOf(parentOf(x));
+                }
+
+                if (colorOf(rightOf(sib)) == BLACK &&
+                    colorOf(leftOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(leftOf(sib)) == BLACK) {
+                        setColor(rightOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateLeft(sib);
+                        sib = leftOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(leftOf(sib), BLACK);
+                    rotateRight(parentOf(x));
+                    x = root;
+                }
+            }
+        }
+
+        setColor(x, BLACK);
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = 919286545866124006L;
+
+    /**
+     * Save the state of the {@code TreeMap} instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <em>size</em> of the TreeMap (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the TreeMap. The key-value mappings are emitted in
+     *             key-order (as determined by the TreeMap's Comparator,
+     *             or by the keys' natural ordering if the TreeMap has no
+     *             Comparator).
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        for (Map.Entry<K, V> e : entrySet()) {
+            s.writeObject(e.getKey());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    /**
+     * Reconstitute the {@code TreeMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        buildFromSorted(size, null, s, null);
+    }
+
+    /** Intended to be called only from TreeSet.readObject */
+    void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)
+        throws java.io.IOException, ClassNotFoundException {
+        buildFromSorted(size, null, s, defaultVal);
+    }
+
+    /** Intended to be called only from TreeSet.addAll */
+    void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
+        try {
+            buildFromSorted(set.size(), set.iterator(), null, defaultVal);
+        } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    /**
+     * Linear time tree building algorithm from sorted data.  Can accept keys
+     * and/or values from iterator or stream. This leads to too many
+     * parameters, but seems better than alternatives.  The four formats
+     * that this method accepts are:
+     *
+     *    1) An iterator of Map.Entries.  (it != null, defaultVal == null).
+     *    2) An iterator of keys.         (it != null, defaultVal != null).
+     *    3) A stream of alternating serialized keys and values.
+     *                                   (it == null, defaultVal == null).
+     *    4) A stream of serialized keys. (it == null, defaultVal != null).
+     *
+     * It is assumed that the comparator of the TreeMap is already set prior
+     * to calling this method.
+     *
+     * @param size the number of keys (or key-value pairs) to be read from
+     *        the iterator or stream
+     * @param it If non-null, new entries are created from entries
+     *        or keys read from this iterator.
+     * @param str If non-null, new entries are created from keys and
+     *        possibly values read from this stream in serialized form.
+     *        Exactly one of it and str should be non-null.
+     * @param defaultVal if non-null, this default value is used for
+     *        each value in the map.  If null, each value is read from
+     *        iterator or stream, as described above.
+     * @throws java.io.IOException propagated from stream reads. This cannot
+     *         occur if str is null.
+     * @throws ClassNotFoundException propagated from readObject.
+     *         This cannot occur if str is null.
+     */
+    private void buildFromSorted(int size, Iterator<?> it,
+                                 java.io.ObjectInputStream str,
+                                 V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        this.size = size;
+        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
+                               it, str, defaultVal);
+    }
+
+    /**
+     * Recursive "helper method" that does the real work of the
+     * previous method.  Identically named parameters have
+     * identical definitions.  Additional parameters are documented below.
+     * It is assumed that the comparator and size fields of the TreeMap are
+     * already set prior to calling this method.  (It ignores both fields.)
+     *
+     * @param level the current level of tree. Initial call should be 0.
+     * @param lo the first element index of this subtree. Initial should be 0.
+     * @param hi the last element index of this subtree.  Initial should be
+     *        size-1.
+     * @param redLevel the level at which nodes should be red.
+     *        Must be equal to computeRedLevel for tree of this size.
+     */
+    @SuppressWarnings("unchecked")
+    private final TreeMapEntry<K,V> buildFromSorted(int level, int lo, int hi,
+                                             int redLevel,
+                                             Iterator<?> it,
+                                             java.io.ObjectInputStream str,
+                                             V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        /*
+         * Strategy: The root is the middlemost element. To get to it, we
+         * have to first recursively construct the entire left subtree,
+         * so as to grab all of its elements. We can then proceed with right
+         * subtree.
+         *
+         * The lo and hi arguments are the minimum and maximum
+         * indices to pull out of the iterator or stream for current subtree.
+         * They are not actually indexed, we just proceed sequentially,
+         * ensuring that items are extracted in corresponding order.
+         */
+
+        if (hi < lo) return null;
+
+        int mid = (lo + hi) >>> 1;
+
+        TreeMapEntry<K,V> left  = null;
+        if (lo < mid)
+            left = buildFromSorted(level+1, lo, mid - 1, redLevel,
+                                   it, str, defaultVal);
+
+        // extract key and/or value from iterator or stream
+        K key;
+        V value;
+        if (it != null) {
+            if (defaultVal==null) {
+                Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next();
+                key = (K)entry.getKey();
+                value = (V)entry.getValue();
+            } else {
+                key = (K)it.next();
+                value = defaultVal;
+            }
+        } else { // use stream
+            key = (K) str.readObject();
+            value = (defaultVal != null ? defaultVal : (V) str.readObject());
+        }
+
+        TreeMapEntry<K,V> middle =  new TreeMapEntry<>(key, value, null);
+
+        // color nodes in non-full bottommost level red
+        if (level == redLevel)
+            middle.color = RED;
+
+        if (left != null) {
+            middle.left = left;
+            left.parent = middle;
+        }
+
+        if (mid < hi) {
+            TreeMapEntry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
+                                               it, str, defaultVal);
+            middle.right = right;
+            right.parent = middle;
+        }
+
+        return middle;
+    }
+
+    /**
+     * Finds the level down to which to assign all nodes BLACK.  This is the
+     * last `full' level of the complete binary tree produced by buildTree.
+     * The remaining nodes are colored RED. (This makes a `nice' set of
+     * color assignments wrt future insertions.) This level number is
+     * computed by finding the number of splits needed to reach the zeroeth
+     * node.
+     *
+     * @param size the (non-negative) number of keys in the tree to be built
+     */
+    private static int computeRedLevel(int size) {
+        return 31 - Integer.numberOfLeadingZeros(size + 1);
+    }
+
+    /**
+     * Currently, we support Spliterator-based versions only for the
+     * full map, in either plain of descending form, otherwise relying
+     * on defaults because size estimation for submaps would dominate
+     * costs. The type tests needed to check these for key views are
+     * not very nice but avoid disrupting existing class
+     * structures. Callers must use plain default spliterators if this
+     * returns null.
+     */
+    static <K> Spliterator<K> keySpliteratorFor(NavigableMap<K,?> m) {
+        if (m instanceof TreeMap) {
+            @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                (TreeMap<K,Object>) m;
+            return t.keySpliterator();
+        }
+        if (m instanceof DescendingSubMap) {
+            @SuppressWarnings("unchecked") DescendingSubMap<K,?> dm =
+                (DescendingSubMap<K,?>) m;
+            TreeMap<K,?> tm = dm.m;
+            if (dm == tm.descendingMap) {
+                @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                    (TreeMap<K,Object>) tm;
+                return t.descendingKeySpliterator();
+            }
+        }
+        @SuppressWarnings("unchecked") NavigableSubMap<K,?> sm =
+            (NavigableSubMap<K,?>) m;
+        return sm.keySpliterator();
+    }
+
+    final Spliterator<K> keySpliterator() {
+        return new KeySpliterator<>(this, null, null, 0, -1, 0);
+    }
+
+    final Spliterator<K> descendingKeySpliterator() {
+        return new DescendingKeySpliterator<>(this, null, null, 0, -2, 0);
+    }
+
+    /**
+     * Base class for spliterators.  Iteration starts at a given
+     * origin and continues up to but not including a given fence (or
+     * null for end).  At top-level, for ascending cases, the first
+     * split uses the root as left-fence/right-origin. From there,
+     * right-hand splits replace the current fence with its left
+     * child, also serving as origin for the split-off spliterator.
+     * Left-hands are symmetric. Descending versions place the origin
+     * at the end and invert ascending split rules.  This base class
+     * is non-committal about directionality, or whether the top-level
+     * spliterator covers the whole tree. This means that the actual
+     * split mechanics are located in subclasses. Some of the subclass
+     * trySplit methods are identical (except for return types), but
+     * not nicely factorable.
+     *
+     * Currently, subclass versions exist only for the full map
+     * (including descending keys via its descendingMap).  Others are
+     * possible but currently not worthwhile because submaps require
+     * O(n) computations to determine size, which substantially limits
+     * potential speed-ups of using custom Spliterators versus default
+     * mechanics.
+     *
+     * To bootstrap initialization, external constructors use
+     * negative size estimates: -1 for ascend, -2 for descend.
+     */
+    static class TreeMapSpliterator<K,V> {
+        final TreeMap<K,V> tree;
+        TreeMapEntry<K,V> current; // traverser; initially first node in range
+        TreeMapEntry<K,V> fence;   // one past last, or null
+        int side;                   // 0: top, -1: is a left split, +1: right
+        int est;                    // size estimate (exact only for top-level)
+        int expectedModCount;       // for CME checks
+
+        TreeMapSpliterator(TreeMap<K,V> tree,
+                           TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                           int side, int est, int expectedModCount) {
+            this.tree = tree;
+            this.current = origin;
+            this.fence = fence;
+            this.side = side;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEstimate() { // force initialization
+            int s; TreeMap<K,V> t;
+            if ((s = est) < 0) {
+                if ((t = tree) != null) {
+                    current = (s == -1) ? t.getFirstEntry() : t.getLastEntry();
+                    s = est = t.size;
+                    expectedModCount = t.modCount;
+                }
+                else
+                    s = est = 0;
+            }
+            return s;
+        }
+
+        public final long estimateSize() {
+            return (long)getEstimate();
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(TreeMap<K,V> tree,
+                       TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                       int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                s = ((e == null || e == f) ? null :      // empty
+                     (d == 0)              ? tree.root : // was top
+                     (d >  0)              ? e.right :   // was right
+                     (d <  0 && f != null) ? f.left :    // was left
+                     null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new KeySpliterator<>
+                    (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        public final Comparator<? super K>  getComparator() {
+            return tree.comparator;
+        }
+
+    }
+
+    static final class DescendingKeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        DescendingKeySpliterator(TreeMap<K,V> tree,
+                                 TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                                 int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public DescendingKeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d <  0)              ? e.left :    // was left
+                         (d >  0 && f != null) ? f.right :   // was right
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) > 0) {       // e not already past s
+                side = 1;
+                return new DescendingKeySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pr;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.left) != null) {
+                        while ((pr = p.right) != null)
+                            p = pr;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.left)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = predecessor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.ORDERED;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+            extends TreeMapSpliterator<K,V>
+            implements Spliterator<V> {
+        ValueSpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new ValueSpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.value);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.value);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) | Spliterator.ORDERED;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new EntrySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                    Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        @Override
+        public Comparator<Map.Entry<K, V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (tree.comparator != null) {
+                return Map.Entry.comparingByKey(tree.comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K, V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/TreeSet.java b/android-35/java/util/TreeSet.java
new file mode 100644
index 0000000..a68c157
--- /dev/null
+++ b/android-35/java/util/TreeSet.java
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link NavigableSet} implementation based on a {@link TreeMap}.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} provided at set creation
+ * time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the basic
+ * operations ({@code add}, {@code remove} and {@code contains}).
+ *
+ * <p>Note that the ordering maintained by a set (whether or not an explicit
+ * comparator is provided) must be <i>consistent with equals</i> if it is to
+ * correctly implement the {@code Set} interface.  (See {@code Comparable}
+ * or {@code Comparator} for a precise definition of <i>consistent with
+ * equals</i>.)  This is so because the {@code Set} interface is defined in
+ * terms of the {@code equals} operation, but a {@code TreeSet} instance
+ * performs all element comparisons using its {@code compareTo} (or
+ * {@code compare}) method, so two elements that are deemed equal by this method
+ * are, from the standpoint of the set, equal.  The behavior of a set
+ * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
+ * just fails to obey the general contract of the {@code Set} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a tree set concurrently, and at least one
+ * of the threads modifies the set, it <i>must</i> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own {@code remove}
+ * method, the iterator will throw a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>The {@link #addFirst addFirst} and {@link #addLast addLast} methods of this class
+ * throw {@code UnsupportedOperationException}. The encounter order of elements is determined
+ * by the comparison method; therefore, explicit positioning is not supported.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     Comparable
+ * @see     Comparator
+ * @see     TreeMap
+ * @since   1.2
+ */
+
+public class TreeSet<E> extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable
+{
+    /**
+     * The backing map.
+     */
+    private transient NavigableMap<E,Object> m;
+
+    // Dummy value to associate with an Object in the backing Map
+    private static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a set backed by the specified navigable map.
+     */
+    TreeSet(NavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the
+     * natural ordering of its elements.  All elements inserted into
+     * the set must implement the {@link Comparable} interface.
+     * Furthermore, all such elements must be <i>mutually
+     * comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.  If the user attempts to add an element
+     * to the set that violates this constraint (for example, the user
+     * attempts to add a string element to a set whose elements are
+     * integers), the {@code add} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeSet() {
+        this(new TreeMap<>());
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the specified
+     * comparator.  All elements inserted into the set must be <i>mutually
+     * comparable</i> by the specified comparator: {@code comparator.compare(e1,
+     * e2)} must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the set.  If the user attempts to add
+     * an element to the set that violates this constraint, the
+     * {@code add} call will throw a {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public TreeSet(Comparator<? super E> comparator) {
+        this(new TreeMap<>(comparator));
+    }
+
+    /**
+     * Constructs a new tree set containing the elements in the specified
+     * collection, sorted according to the <i>natural ordering</i> of its
+     * elements.  All elements inserted into the set must implement the
+     * {@link Comparable} interface.  Furthermore, all such elements must be
+     * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.
+     *
+     * @param c collection whose elements will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection is null
+     */
+    public TreeSet(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new tree set containing the same elements and
+     * using the same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set is null
+     */
+    public TreeSet(SortedSet<E> s) {
+        this(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<E> descendingSet() {
+        return new TreeSet<>(m.descendingMap());
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean add(E e) {
+        return m.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code Objects.equals(o, e)},
+     * if this set contains such an element.  Returns {@code true} if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean remove(Object o) {
+        return m.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the elements provided cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified collection is null or
+     *         if any element is null and this set uses natural ordering, or
+     *         its comparator does not permit null elements
+     */
+    public  boolean addAll(Collection<? extends E> c) {
+        // Use linear-time version if applicable
+        if (m.size()==0 && c.size() > 0 &&
+            c instanceof SortedSet &&
+                m instanceof TreeMap<E, Object> map) {
+            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
+            if (Objects.equals(set.comparator(), map.comparator())) {
+                map.addAllForTreeSet(set, PRESENT);
+                return true;
+            }
+        }
+        return super.addAll(c);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or {@code toElement}
+     *         is null and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                  E toElement,   boolean toInclusive) {
+        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
+                                       toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new TreeSet<>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new TreeSet<>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set uses natural ordering,
+     *         or its comparator does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    // NavigableSet API methods
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollFirst() {
+        Map.Entry<E,?> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollLast() {
+        Map.Entry<E,?> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public void addFirst(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public void addLast(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeSet} instance. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        TreeSet<E> clone;
+        try {
+            clone = (TreeSet<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        clone.m = new TreeMap<>(m);
+        return clone;
+    }
+
+    /**
+     * Save the state of the {@code TreeSet} instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData Emits the comparator used to order this set, or
+     *             {@code null} if it obeys its elements' natural ordering
+     *             (Object), followed by the size of the set (the number of
+     *             elements it contains) (int), followed by all of its
+     *             elements (each an Object) in order (as determined by the
+     *             set's Comparator, or by the elements' natural ordering if
+     *             the set has no Comparator).
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out Comparator
+        s.writeObject(m.comparator());
+
+        // Write out size
+        s.writeInt(m.size());
+
+        // Write out all elements in the proper order.
+        for (E e : m.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the {@code TreeSet} instance from a stream (that is,
+     * deserialize it).
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden stuff
+        s.defaultReadObject();
+
+        // Read in Comparator
+        @SuppressWarnings("unchecked")
+            Comparator<? super E> c = (Comparator<? super E>) s.readObject();
+
+        // Create backing TreeMap
+        TreeMap<E,Object> tm = new TreeMap<>(c);
+        m = tm;
+
+        // Read in size
+        int size = s.readInt();
+
+        tm.readTreeSet(size, s, PRESENT);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return TreeMap.keySpliteratorFor(m);
+    }
+
+    @java.io.Serial
+    private static final long serialVersionUID = -2479143000061671589L;
+}
diff --git a/android-35/java/util/Tripwire.java b/android-35/java/util/Tripwire.java
new file mode 100644
index 0000000..c807a41
--- /dev/null
+++ b/android-35/java/util/Tripwire.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import sun.util.logging.PlatformLogger;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    @SuppressWarnings("removal")
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/android-35/java/util/UUID.java b/android-35/java/util/UUID.java
new file mode 100644
index 0000000..9808868
--- /dev/null
+++ b/android-35/java/util/UUID.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+
+import java.security.*;
+
+/**
+ * A class that represents an immutable universally unique identifier (UUID).
+ * A UUID represents a 128-bit value.
+ *
+ * <p> There exist different variants of these global identifiers.  The methods
+ * of this class are for manipulating the Leach-Salz variant, although the
+ * constructors allow the creation of any variant of UUID (described below).
+ *
+ * <p> The layout of a variant 2 (Leach-Salz) UUID is as follows:
+ *
+ * The most significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xFFFFFFFF00000000 time_low
+ * 0x00000000FFFF0000 time_mid
+ * 0x000000000000F000 version
+ * 0x0000000000000FFF time_hi
+ * </pre>
+ * The least significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xC000000000000000 variant
+ * 0x3FFF000000000000 clock_seq
+ * 0x0000FFFFFFFFFFFF node
+ * </pre>
+ *
+ * <p> The variant field contains a value which identifies the layout of the
+ * {@code UUID}.  The bit layout described above is valid only for a {@code
+ * UUID} with a variant value of 2, which indicates the Leach-Salz variant.
+ *
+ * <p> The version field holds a value that describes the type of this {@code
+ * UUID}.  There are four different basic types of UUIDs: time-based, DCE
+ * security, name-based, and randomly generated UUIDs.  These types have a
+ * version value of 1, 2, 3 and 4, respectively.
+ *
+ * <p> For more information including algorithms used to create {@code UUID}s,
+ * see <a href="http://www.ietf.org/rfc/rfc4122.txt"> <i>RFC&nbsp;4122: A
+ * Universally Unique IDentifier (UUID) URN Namespace</i></a>, section 4.2
+ * &quot;Algorithms for Creating a Time-Based UUID&quot;.
+ *
+ * @since   1.5
+ */
+public final class UUID implements java.io.Serializable, Comparable<UUID> {
+
+    /**
+     * Explicit serialVersionUID for interoperability.
+     */
+    @java.io.Serial
+    private static final long serialVersionUID = -4856846361193249489L;
+
+    /*
+     * The most significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long mostSigBits;
+
+    /*
+     * The least significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long leastSigBits;
+
+    // Android-removed: not using JavaLangAccess.fastUUID.
+    // private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+
+    /*
+     * The random number generator used by this class to create random
+     * based UUIDs. In a holder class to defer initialization until needed.
+     */
+    private static class Holder {
+        static final SecureRandom numberGenerator = new SecureRandom();
+    }
+
+    // Constructors and Factories
+
+    /*
+     * Private constructor which uses a byte array to construct the new UUID.
+     */
+    private UUID(byte[] data) {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i=0; i<8; i++)
+            msb = (msb << 8) | (data[i] & 0xff);
+        for (int i=8; i<16; i++)
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * Constructs a new {@code UUID} using the specified data.  {@code
+     * mostSigBits} is used for the most significant 64 bits of the {@code
+     * UUID} and {@code leastSigBits} becomes the least significant 64 bits of
+     * the {@code UUID}.
+     *
+     * @param  mostSigBits
+     *         The most significant bits of the {@code UUID}
+     *
+     * @param  leastSigBits
+     *         The least significant bits of the {@code UUID}
+     */
+    public UUID(long mostSigBits, long leastSigBits) {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
+     *
+     * The {@code UUID} is generated using a cryptographically strong pseudo
+     * random number generator.
+     *
+     * @return  A randomly generated {@code UUID}
+     */
+    public static UUID randomUUID() {
+        SecureRandom ng = Holder.numberGenerator;
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6]  &= 0x0f;  /* clear version        */
+        randomBytes[6]  |= 0x40;  /* set to version 4     */
+        randomBytes[8]  &= 0x3f;  /* clear variant        */
+        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * Static factory to retrieve a type 3 (name based) {@code UUID} based on
+     * the specified byte array.
+     *
+     * @param  name
+     *         A byte array to be used to construct a {@code UUID}
+     *
+     * @return  A {@code UUID} generated from the specified array
+     */
+    public static UUID nameUUIDFromBytes(byte[] name) {
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new InternalError("MD5 not supported", nsae);
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6]  &= 0x0f;  /* clear version        */
+        md5Bytes[6]  |= 0x30;  /* set to version 3     */
+        md5Bytes[8]  &= 0x3f;  /* clear variant        */
+        md5Bytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(md5Bytes);
+    }
+
+    private static final byte[] NIBBLES;
+    static {
+        byte[] ns = new byte[256];
+        Arrays.fill(ns, (byte) -1);
+        ns['0'] = 0;
+        ns['1'] = 1;
+        ns['2'] = 2;
+        ns['3'] = 3;
+        ns['4'] = 4;
+        ns['5'] = 5;
+        ns['6'] = 6;
+        ns['7'] = 7;
+        ns['8'] = 8;
+        ns['9'] = 9;
+        ns['A'] = 10;
+        ns['B'] = 11;
+        ns['C'] = 12;
+        ns['D'] = 13;
+        ns['E'] = 14;
+        ns['F'] = 15;
+        ns['a'] = 10;
+        ns['b'] = 11;
+        ns['c'] = 12;
+        ns['d'] = 13;
+        ns['e'] = 14;
+        ns['f'] = 15;
+        NIBBLES = ns;
+    }
+
+    private static long parse4Nibbles(String name, int pos) {
+        byte[] ns = NIBBLES;
+        char ch1 = name.charAt(pos);
+        char ch2 = name.charAt(pos + 1);
+        char ch3 = name.charAt(pos + 2);
+        char ch4 = name.charAt(pos + 3);
+        return (ch1 | ch2 | ch3 | ch4) > 0xff ?
+                -1 : ns[ch1] << 12 | ns[ch2] << 8 | ns[ch3] << 4 | ns[ch4];
+    }
+
+    /**
+     * Since Android 14 {@link #fromString} does more strict input argument
+     * validation.
+     *
+     * This flag is enabled for apps targeting Android 14+.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.UPSIDE_DOWN_CAKE)
+    public static final long ENABLE_STRICT_VALIDATION = 263076149L;
+
+    /**
+     * Creates a {@code UUID} from the string standard representation as
+     * described in the {@link #toString} method.
+     *
+     * @param  name
+     *         A string that specifies a {@code UUID}
+     *
+     * @return  A {@code UUID} with the specified value
+     *
+     * @throws  IllegalArgumentException
+     *          If name does not conform to the string representation as
+     *          described in {@link #toString}
+     *
+     */
+    public static UUID fromString(String name) {
+        // BEGIN Android-changed: Java 8 behaviour is more lenient and the new implementation
+        // might break apps (b/254278943).
+        // Using old implementation for apps targeting Android older than U.
+        if (!(VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE
+                && Compatibility.isChangeEnabled(ENABLE_STRICT_VALIDATION))) {
+            return fromStringJava8(name);
+        }
+
+        return fromStringCurrentJava(name);
+        // END Android-changed: Java 8 behaviour is more lenient and the new implementation
+        // might break apps (b/254278943).
+    }
+
+    /**
+     * Extracted for testing purposes only.
+     * @hide
+     */
+    public static UUID fromStringCurrentJava(String name) {
+        if (name.length() == 36) {
+            char ch1 = name.charAt(8);
+            char ch2 = name.charAt(13);
+            char ch3 = name.charAt(18);
+            char ch4 = name.charAt(23);
+            if (ch1 == '-' && ch2 == '-' && ch3 == '-' && ch4 == '-') {
+                long msb1 = parse4Nibbles(name, 0);
+                long msb2 = parse4Nibbles(name, 4);
+                long msb3 = parse4Nibbles(name, 9);
+                long msb4 = parse4Nibbles(name, 14);
+                long lsb1 = parse4Nibbles(name, 19);
+                long lsb2 = parse4Nibbles(name, 24);
+                long lsb3 = parse4Nibbles(name, 28);
+                long lsb4 = parse4Nibbles(name, 32);
+                if ((msb1 | msb2 | msb3 | msb4 | lsb1 | lsb2 | lsb3 | lsb4) >= 0) {
+                    return new UUID(
+                            msb1 << 48 | msb2 << 32 | msb3 << 16 | msb4,
+                            lsb1 << 48 | lsb2 << 32 | lsb3 << 16 | lsb4);
+                }
+            }
+        }
+        return fromString1(name);
+    }
+
+    private static UUID fromString1(String name) {
+        int len = name.length();
+        if (len > 36) {
+            throw new IllegalArgumentException("UUID string too large");
+        }
+
+        int dash1 = name.indexOf('-', 0);
+        int dash2 = name.indexOf('-', dash1 + 1);
+        int dash3 = name.indexOf('-', dash2 + 1);
+        int dash4 = name.indexOf('-', dash3 + 1);
+        int dash5 = name.indexOf('-', dash4 + 1);
+
+        // For any valid input, dash1 through dash4 will be positive and dash5
+        // negative, but it's enough to check dash4 and dash5:
+        // - if dash1 is -1, dash4 will be -1
+        // - if dash1 is positive but dash2 is -1, dash4 will be -1
+        // - if dash1 and dash2 is positive, dash3 will be -1, dash4 will be
+        //   positive, but so will dash5
+        if (dash4 < 0 || dash5 >= 0) {
+            throw new IllegalArgumentException("Invalid UUID string: " + name);
+        }
+
+        long mostSigBits = Long.parseLong(name, 0, dash1, 16) & 0xffffffffL;
+        mostSigBits <<= 16;
+        mostSigBits |= Long.parseLong(name, dash1 + 1, dash2, 16) & 0xffffL;
+        mostSigBits <<= 16;
+        mostSigBits |= Long.parseLong(name, dash2 + 1, dash3, 16) & 0xffffL;
+        long leastSigBits = Long.parseLong(name, dash3 + 1, dash4, 16) & 0xffffL;
+        leastSigBits <<= 48;
+        leastSigBits |= Long.parseLong(name, dash4 + 1, len, 16) & 0xffffffffffffL;
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    /**
+     * Extracted for testing purposes only.
+     * @hide
+     */
+    public static UUID fromStringJava8(String name) {
+        String[] components = name.split("-");
+        if (components.length != 5)
+            throw new IllegalArgumentException("Invalid UUID string: "+ name);
+        for (int i=0; i<5; i++)
+            components[i] = "0x"+components[i];
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    // Field Accessor Methods
+
+    /**
+     * Returns the least significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The least significant 64 bits of this UUID's 128 bit value
+     */
+    public long getLeastSignificantBits() {
+        return leastSigBits;
+    }
+
+    /**
+     * Returns the most significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The most significant 64 bits of this UUID's 128 bit value
+     */
+    public long getMostSignificantBits() {
+        return mostSigBits;
+    }
+
+    /**
+     * The version number associated with this {@code UUID}.  The version
+     * number describes how this {@code UUID} was generated.
+     *
+     * The version number has the following meaning:
+     * <ul>
+     * <li>1    Time-based UUID
+     * <li>2    DCE security UUID
+     * <li>3    Name-based UUID
+     * <li>4    Randomly generated UUID
+     * </ul>
+     *
+     * @return  The version number of this {@code UUID}
+     */
+    public int version() {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int)((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * The variant number associated with this {@code UUID}.  The variant
+     * number describes the layout of the {@code UUID}.
+     *
+     * The variant number has the following meaning:
+     * <ul>
+     * <li>0    Reserved for NCS backward compatibility
+     * <li>2    <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>
+     * (Leach-Salz), used by this class
+     * <li>6    Reserved, Microsoft Corporation backward compatibility
+     * <li>7    Reserved for future definition
+     * </ul>
+     *
+     * @return  The variant number of this {@code UUID}
+     */
+    public int variant() {
+        // This field is composed of a varying number of bits.
+        // 0    -    -    Reserved for NCS backward compatibility
+        // 1    0    -    The IETF aka Leach-Salz variant (used by this class)
+        // 1    1    0    Reserved, Microsoft backward compatibility
+        // 1    1    1    Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
+                      & (leastSigBits >> 63));
+    }
+
+    /**
+     * The timestamp value associated with this UUID.
+     *
+     * <p> The 60 bit timestamp value is constructed from the time_low,
+     * time_mid, and time_hi fields of this {@code UUID}.  The resulting
+     * timestamp is measured in 100-nanosecond units since midnight,
+     * October 15, 1582 UTC.
+     *
+     * <p> The timestamp value is only meaningful in a time-based UUID, which
+     * has version type 1.  If this {@code UUID} is not a time-based UUID then
+     * this method throws UnsupportedOperationException.
+     *
+     * @throws UnsupportedOperationException
+     *         If this UUID is not a version 1 UUID
+     * @return The timestamp of this {@code UUID}.
+     */
+    public long timestamp() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (mostSigBits & 0x0FFFL) << 48
+             | ((mostSigBits >> 16) & 0x0FFFFL) << 32
+             | mostSigBits >>> 32;
+    }
+
+    /**
+     * The clock sequence value associated with this UUID.
+     *
+     * <p> The 14 bit clock sequence value is constructed from the clock
+     * sequence field of this UUID.  The clock sequence field is used to
+     * guarantee temporal uniqueness in a time-based UUID.
+     *
+     * <p> The {@code clockSequence} value is only meaningful in a time-based
+     * UUID, which has version type 1.  If this UUID is not a time-based UUID
+     * then this method throws UnsupportedOperationException.
+     *
+     * @return  The clock sequence of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public int clockSequence() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (int)((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * The node value associated with this UUID.
+     *
+     * <p> The 48 bit node value is constructed from the node field of this
+     * UUID.  This field is intended to hold the IEEE 802 address of the machine
+     * that generated this UUID to guarantee spatial uniqueness.
+     *
+     * <p> The node value is only meaningful in a time-based UUID, which has
+     * version type 1.  If this UUID is not a time-based UUID then this method
+     * throws UnsupportedOperationException.
+     *
+     * @return  The node value of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public long node() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    // Object Inherited Methods
+
+    /**
+     * Returns a {@code String} object representing this {@code UUID}.
+     *
+     * <p> The UUID string representation is as described by this BNF:
+     * <blockquote><pre>
+     * {@code
+     * UUID                   = <time_low> "-" <time_mid> "-"
+     *                          <time_high_and_version> "-"
+     *                          <variant_and_sequence> "-"
+     *                          <node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               =
+     *       "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+     *       | "a" | "b" | "c" | "d" | "e" | "f"
+     *       | "A" | "B" | "C" | "D" | "E" | "F"
+     * }</pre></blockquote>
+     *
+     * @return  A string representation of this {@code UUID}
+     */
+    @Override
+    public String toString() {
+        // Android-changed: using old implementation.
+        // return jla.fastUUID(leastSigBits, mostSigBits);
+        return (digits(mostSigBits >> 32, 8) + "-" +
+                digits(mostSigBits >> 16, 4) + "-" +
+                digits(mostSigBits, 4) + "-" +
+                digits(leastSigBits >> 48, 4) + "-" +
+                digits(leastSigBits, 12));
+    }
+
+    /** Returns val represented by the specified number of hex digits. */
+    private static String digits(long val, int digits) {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * Returns a hash code for this {@code UUID}.
+     *
+     * @return  A hash code value for this {@code UUID}
+     */
+    @Override
+    public int hashCode() {
+        long hilo = mostSigBits ^ leastSigBits;
+        return ((int)(hilo >> 32)) ^ (int) hilo;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null}, is a {@code UUID}
+     * object, has the same variant, and contains the same value, bit for bit,
+     * as this {@code UUID}.
+     *
+     * @param  obj
+     *         The object to be compared
+     *
+     * @return  {@code true} if the objects are the same; {@code false}
+     *          otherwise
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if ((null == obj) || (obj.getClass() != UUID.class))
+            return false;
+        UUID id = (UUID)obj;
+        return (mostSigBits == id.mostSigBits &&
+                leastSigBits == id.leastSigBits);
+    }
+
+    // Comparison Operations
+
+    /**
+     * Compares this UUID with the specified UUID.
+     *
+     * <p> The first of two UUIDs is greater than the second if the most
+     * significant field in which the UUIDs differ is greater for the first
+     * UUID.
+     *
+     * @param  val
+     *         {@code UUID} to which this {@code UUID} is to be compared
+     *
+     * @return  -1, 0 or 1 as this {@code UUID} is less than, equal to, or
+     *          greater than {@code val}
+     *
+     */
+    @Override
+    public int compareTo(UUID val) {
+        // The ordering is intentionally set up so that the UUIDs
+        // can simply be numerically compared as two numbers
+        return (this.mostSigBits < val.mostSigBits ? -1 :
+                (this.mostSigBits > val.mostSigBits ? 1 :
+                 (this.leastSigBits < val.leastSigBits ? -1 :
+                  (this.leastSigBits > val.leastSigBits ? 1 :
+                   0))));
+    }
+}
diff --git a/android-35/java/util/UnknownFormatConversionException.java b/android-35/java/util/UnknownFormatConversionException.java
new file mode 100644
index 0000000..07519ad
--- /dev/null
+++ b/android-35/java/util/UnknownFormatConversionException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown conversion is given.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to
+ * any method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatConversionException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 19060418L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unknown conversion.
+     *
+     * @param  s
+     *         Unknown conversion
+     */
+    public UnknownFormatConversionException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unknown conversion.
+     *
+     * @return  The unknown conversion.
+     */
+    public String getConversion() {
+        return s;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("Conversion = '%s'", s);
+    }
+}
diff --git a/android-35/java/util/UnknownFormatFlagsException.java b/android-35/java/util/UnknownFormatFlagsException.java
new file mode 100644
index 0000000..c498711
--- /dev/null
+++ b/android-35/java/util/UnknownFormatFlagsException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown flag is given.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatFlagsException extends IllegalFormatException {
+
+    @java.io.Serial
+    private static final long serialVersionUID = 19370506L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an unknown flag
+     */
+    public UnknownFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an unknown flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return "Flags = " + flags;
+    }
+}
diff --git a/android-35/java/util/Vector.java b/android-35/java/util/Vector.java
new file mode 100644
index 0000000..7dbf760
--- /dev/null
+++ b/android-35/java/util/Vector.java
@@ -0,0 +1,1508 @@
+/*
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.StreamCorruptedException;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * The {@code Vector} class implements a growable array of
+ * objects. Like an array, it contains components that can be
+ * accessed using an integer index. However, the size of a
+ * {@code Vector} can grow or shrink as needed to accommodate
+ * adding and removing items after the {@code Vector} has been created.
+ *
+ * <p>Each vector tries to optimize storage management by maintaining a
+ * {@code capacity} and a {@code capacityIncrement}. The
+ * {@code capacity} is always at least as large as the vector
+ * size; it is usually larger because as components are added to the
+ * vector, the vector's storage increases in chunks the size of
+ * {@code capacityIncrement}. An application can increase the
+ * capacity of a vector before inserting a large number of
+ * components; this reduces the amount of incremental reallocation.
+ *
+ * <p id="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:
+ * if the vector is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) add} methods, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of
+ * concurrent modification, the iterator fails quickly and cleanly, rather
+ * than risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.  The {@link Enumeration Enumerations} returned by
+ * the {@link #elements() elements} method are <em>not</em> fail-fast; if the
+ * Vector is structurally modified at any time after the enumeration is
+ * created then the results of enumerating are undefined.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link List} interface, making it a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Vector} is synchronized.  If a thread-safe
+ * implementation is not needed, it is recommended to use {@link
+ * ArrayList} in place of {@code Vector}.
+ *
+ * @param <E> Type of component elements
+ *
+ * @author  Lee Boynton
+ * @author  Jonathan Payne
+ * @see Collection
+ * @see LinkedList
+ * @since   1.0
+ */
+public class Vector<E>
+    extends AbstractList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    /**
+     * The array buffer into which the components of the vector are
+     * stored. The capacity of the vector is the length of this array buffer,
+     * and is at least large enough to contain all the vector's elements.
+     *
+     * <p>Any array elements following the last element in the Vector are null.
+     *
+     * @serial
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    protected Object[] elementData;
+
+    /**
+     * The number of valid components in this {@code Vector} object.
+     * Components {@code elementData[0]} through
+     * {@code elementData[elementCount-1]} are the actual items.
+     *
+     * @serial
+     */
+    protected int elementCount;
+
+    /**
+     * The amount by which the capacity of the vector is automatically
+     * incremented when its size becomes greater than its capacity.  If
+     * the capacity increment is less than or equal to zero, the capacity
+     * of the vector is doubled each time it needs to grow.
+     *
+     * @serial
+     */
+    protected int capacityIncrement;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    @java.io.Serial
+    private static final long serialVersionUID = -2767605614048989439L;
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * capacity increment.
+     *
+     * @param   initialCapacity     the initial capacity of the vector
+     * @param   capacityIncrement   the amount by which the capacity is
+     *                              increased when the vector overflows
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity, int capacityIncrement) {
+        super();
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        this.elementData = new Object[initialCapacity];
+        this.capacityIncrement = capacityIncrement;
+    }
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * with its capacity increment equal to zero.
+     *
+     * @param   initialCapacity   the initial capacity of the vector
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity) {
+        this(initialCapacity, 0);
+    }
+
+    /**
+     * Constructs an empty vector so that its internal data array
+     * has size {@code 10} and its standard capacity increment is
+     * zero.
+     */
+    public Vector() {
+        this(10);
+    }
+
+    /**
+     * Constructs a vector containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this
+     *       vector
+     * @throws NullPointerException if the specified collection is null
+     * @since   1.2
+     */
+    public Vector(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        elementCount = a.length;
+        if (c.getClass() == ArrayList.class) {
+            elementData = a;
+        } else {
+            elementData = Arrays.copyOf(a, elementCount, Object[].class);
+        }
+    }
+
+    /**
+     * Copies the components of this vector into the specified array.
+     * The item at index {@code k} in this vector is copied into
+     * component {@code k} of {@code anArray}.
+     *
+     * @param  anArray the array into which the components get copied
+     * @throws NullPointerException if the given array is null
+     * @throws IndexOutOfBoundsException if the specified array is not
+     *         large enough to hold all the components of this vector
+     * @throws ArrayStoreException if a component of this vector is not of
+     *         a runtime type that can be stored in the specified array
+     * @see #toArray(Object[])
+     */
+    public synchronized void copyInto(Object[] anArray) {
+        System.arraycopy(elementData, 0, anArray, 0, elementCount);
+    }
+
+    /**
+     * Trims the capacity of this vector to be the vector's current
+     * size. If the capacity of this vector is larger than its current
+     * size, then the capacity is changed to equal the size by replacing
+     * its internal data array, kept in the field {@code elementData},
+     * with a smaller one. An application can use this operation to
+     * minimize the storage of a vector.
+     */
+    public synchronized void trimToSize() {
+        modCount++;
+        int oldCapacity = elementData.length;
+        if (elementCount < oldCapacity) {
+            elementData = Arrays.copyOf(elementData, elementCount);
+        }
+    }
+
+    /**
+     * Increases the capacity of this vector, if necessary, to ensure
+     * that it can hold at least the number of components specified by
+     * the minimum capacity argument.
+     *
+     * <p>If the current capacity of this vector is less than
+     * {@code minCapacity}, then its capacity is increased by replacing its
+     * internal data array, kept in the field {@code elementData}, with a
+     * larger one.  The size of the new data array will be the old size plus
+     * {@code capacityIncrement}, unless the value of
+     * {@code capacityIncrement} is less than or equal to zero, in which case
+     * the new capacity will be twice the old capacity; but if this new size
+     * is still smaller than {@code minCapacity}, then the new capacity will
+     * be {@code minCapacity}.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    public synchronized void ensureCapacity(int minCapacity) {
+        if (minCapacity > 0) {
+            modCount++;
+            if (minCapacity > elementData.length)
+                grow(minCapacity);
+        }
+    }
+
+    /**
+     * Increases the capacity to ensure that it can hold at least the
+     * number of elements specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     * @throws OutOfMemoryError if minCapacity is less than zero
+     */
+    private Object[] grow(int minCapacity) {
+        int oldCapacity = elementData.length;
+        int newCapacity = ArraysSupport.newLength(oldCapacity,
+                minCapacity - oldCapacity, /* minimum growth */
+                capacityIncrement > 0 ? capacityIncrement : oldCapacity
+                                           /* preferred growth */);
+        return elementData = Arrays.copyOf(elementData, newCapacity);
+    }
+
+    private Object[] grow() {
+        return grow(elementCount + 1);
+    }
+
+    /**
+     * Sets the size of this vector. If the new size is greater than the
+     * current size, new {@code null} items are added to the end of
+     * the vector. If the new size is less than the current size, all
+     * components at index {@code newSize} and greater are discarded.
+     *
+     * @param  newSize   the new size of this vector
+     * @throws ArrayIndexOutOfBoundsException if the new size is negative
+     */
+    public synchronized void setSize(int newSize) {
+        modCount++;
+        if (newSize > elementData.length)
+            grow(newSize);
+        final Object[] es = elementData;
+        for (int to = elementCount, i = newSize; i < to; i++)
+            es[i] = null;
+        elementCount = newSize;
+    }
+
+    /**
+     * Returns the current capacity of this vector.
+     *
+     * @return  the current capacity (the length of its internal
+     *          data array, kept in the field {@code elementData}
+     *          of this vector)
+     */
+    public synchronized int capacity() {
+        return elementData.length;
+    }
+
+    /**
+     * Returns the number of components in this vector.
+     *
+     * @return  the number of components in this vector
+     */
+    public synchronized int size() {
+        return elementCount;
+    }
+
+    /**
+     * Tests if this vector has no components.
+     *
+     * @return  {@code true} if and only if this vector has
+     *          no components, that is, its size is zero;
+     *          {@code false} otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return elementCount == 0;
+    }
+
+    /**
+     * Returns an enumeration of the components of this vector. The
+     * returned {@code Enumeration} object will generate all items in
+     * this vector. The first item generated is the item at index {@code 0},
+     * then the item at index {@code 1}, and so on. If the vector is
+     * structurally modified while enumerating over the elements then the
+     * results of enumerating are undefined.
+     *
+     * @return  an enumeration of the components of this vector
+     * @see     Iterator
+     */
+    public Enumeration<E> elements() {
+        return new Enumeration<E>() {
+            int count = 0;
+
+            public boolean hasMoreElements() {
+                return count < elementCount;
+            }
+
+            public E nextElement() {
+                synchronized (Vector.this) {
+                    if (count < elementCount) {
+                        return elementData(count++);
+                    }
+                }
+                throw new NoSuchElementException("Vector Enumeration");
+            }
+        };
+    }
+
+    /**
+     * Returns {@code true} if this vector contains the specified element.
+     * More formally, returns {@code true} if and only if this vector
+     * contains at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this vector is to be tested
+     * @return {@code true} if this vector contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o, 0) >= 0;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public int indexOf(Object o) {
+        return indexOf(o, 0);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this vector, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code (i >= index && Objects.equals(o, get(i)))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this vector at position {@code index} or later in the vector;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @see     Object#equals(Object)
+     */
+    public synchronized int indexOf(Object o, int index) {
+        if (o == null) {
+            for (int i = index ; i < elementCount ; i++)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index ; i < elementCount ; i++)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public synchronized int lastIndexOf(Object o) {
+        return lastIndexOf(o, elementCount-1);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this vector, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * {@code (i <= index && Objects.equals(o, get(i)))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this vector;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this vector
+     */
+    public synchronized int lastIndexOf(Object o, int index) {
+        if (index >= elementCount)
+            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
+
+        if (o == null) {
+            for (int i = index; i >= 0; i--)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the component at the specified index.
+     *
+     * <p>This method is identical in functionality to the {@link #get(int)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param      index   an index into this vector
+     * @return     the component at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized E elementAt(int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
+        }
+
+        return elementData(index);
+    }
+
+    /**
+     * Returns the first component (the item at index {@code 0}) of
+     * this vector.
+     *
+     * @return     the first component of this vector
+     * @throws NoSuchElementException if this vector has no components
+     */
+    public synchronized E firstElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(0);
+    }
+
+    /**
+     * Returns the last component of the vector.
+     *
+     * @return  the last component of the vector, i.e., the component at index
+     *          {@code size() - 1}
+     * @throws NoSuchElementException if this vector is empty
+     */
+    public synchronized E lastElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(elementCount - 1);
+    }
+
+    /**
+     * Sets the component at the specified {@code index} of this
+     * vector to be the specified object. The previous component at that
+     * position is discarded.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #set(int, Object) set(int, E)}
+     * method (which is part of the {@link List} interface). Note that the
+     * {@code set} method reverses the order of the parameters, to more closely
+     * match array usage.  Note also that the {@code set} method returns the
+     * old value that was stored at the specified position.
+     *
+     * @param      obj     what the component is to be set to
+     * @param      index   the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void setElementAt(E obj, int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        elementData[index] = obj;
+    }
+
+    /**
+     * Deletes the component at the specified index. Each component in
+     * this vector with an index greater or equal to the specified
+     * {@code index} is shifted downward to have an index one
+     * smaller than the value it had previously. The size of this vector
+     * is decreased by {@code 1}.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the {@link #remove(int)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code remove} method returns the old value that was stored at the
+     * specified position.
+     *
+     * @param      index   the index of the object to remove
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void removeElementAt(int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        else if (index < 0) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+        int j = elementCount - index - 1;
+        if (j > 0) {
+            System.arraycopy(elementData, index + 1, elementData, index, j);
+        }
+        modCount++;
+        elementCount--;
+        elementData[elementCount] = null; /* to let gc do its work */
+    }
+
+    /**
+     * Inserts the specified object as a component in this vector at the
+     * specified {@code index}. Each component in this vector with
+     * an index greater or equal to the specified {@code index} is
+     * shifted upward to have an index one greater than the value it had
+     * previously.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than or equal to the current size of the vector. (If the
+     * index is equal to the current size of the vector, the new element
+     * is appended to the Vector.)
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(int, Object) add(int, E)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code add} method reverses the order of the parameters, to more closely
+     * match array usage.
+     *
+     * @param      obj     the component to insert
+     * @param      index   where to insert the new component
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    public synchronized void insertElementAt(E obj, int index) {
+        if (index > elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index
+                                                     + " > " + elementCount);
+        }
+        modCount++;
+        final int s = elementCount;
+        Object[] elementData = this.elementData;
+        if (s == elementData.length)
+            elementData = grow();
+        System.arraycopy(elementData, index,
+                         elementData, index + 1,
+                         s - index);
+        elementData[index] = obj;
+        elementCount = s + 1;
+    }
+
+    /**
+     * Adds the specified component to the end of this vector,
+     * increasing its size by one. The capacity of this vector is
+     * increased if its size becomes greater than its capacity.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(Object) add(E)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param   obj   the component to be added
+     */
+    public synchronized void addElement(E obj) {
+        modCount++;
+        add(obj, elementData, elementCount);
+    }
+
+    /**
+     * Removes the first (lowest-indexed) occurrence of the argument
+     * from this vector. If the object is found in this vector, each
+     * component in the vector with an index greater or equal to the
+     * object's index is shifted downward to have an index one smaller
+     * than the value it had previously.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #remove(Object)} method (which is part of the
+     * {@link List} interface).
+     *
+     * @param   obj   the component to be removed
+     * @return  {@code true} if the argument was a component of this
+     *          vector; {@code false} otherwise.
+     */
+    public synchronized boolean removeElement(Object obj) {
+        modCount++;
+        int i = indexOf(obj);
+        if (i >= 0) {
+            removeElementAt(i);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes all components from this vector and sets its size to zero.
+     *
+     * <p>This method is identical in functionality to the {@link #clear}
+     * method (which is part of the {@link List} interface).
+     */
+    public synchronized void removeAllElements() {
+        final Object[] es = elementData;
+        for (int to = elementCount, i = elementCount = 0; i < to; i++)
+            es[i] = null;
+        modCount++;
+    }
+
+    /**
+     * Returns a clone of this vector. The copy will contain a
+     * reference to a clone of the internal data array, not a reference
+     * to the original internal data array of this {@code Vector} object.
+     *
+     * @return  a clone of this vector
+     */
+    public synchronized Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            Vector<E> v = (Vector<E>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, elementCount);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector
+     * in the correct order.
+     *
+     * @since 1.2
+     */
+    public synchronized Object[] toArray() {
+        return Arrays.copyOf(elementData, elementCount);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector in the
+     * correct order; the runtime type of the returned array is that of the
+     * specified array.  If the Vector fits in the specified array, it is
+     * returned therein.  Otherwise, a new array is allocated with the runtime
+     * type of the specified array and the size of this Vector.
+     *
+     * <p>If the Vector fits in the specified array with room to spare
+     * (i.e., the array has more elements than the Vector),
+     * the element in the array immediately following the end of the
+     * Vector is set to null.  (This is useful in determining the length
+     * of the Vector <em>only</em> if the caller knows that the Vector
+     * does not contain any null elements.)
+     *
+     * @param <T> type of array elements. The same type as {@code <E>} or a
+     * supertype of {@code <E>}.
+     * @param a the array into which the elements of the Vector are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the Vector
+     * @throws ArrayStoreException if the runtime type of a, {@code <T>}, is not
+     * a supertype of the runtime type, {@code <E>}, of every element in this
+     * Vector
+     * @throws NullPointerException if the given array is null
+     * @since 1.2
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized <T> T[] toArray(T[] a) {
+        if (a.length < elementCount)
+            return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
+
+        System.arraycopy(elementData, 0, a, 0, elementCount);
+
+        if (a.length > elementCount)
+            a[elementCount] = null;
+
+        return a;
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    E elementData(int index) {
+        return (E) elementData[index];
+    }
+
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
+    /**
+     * Returns the element at the specified position in this Vector.
+     *
+     * @param index index of the element to return
+     * @return object at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *            ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E get(int index) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        return elementData(index);
+    }
+
+    /**
+     * Replaces the element at the specified position in this Vector with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E set(int index, E element) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        E oldValue = elementData(index);
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * This helper method split out from add(E) to keep method
+     * bytecode size under 35 (the -XX:MaxInlineSize default value),
+     * which helps when add(E) is called in a C1-compiled loop.
+     */
+    private void add(E e, Object[] elementData, int s) {
+        if (s == elementData.length)
+            elementData = grow();
+        elementData[s] = e;
+        elementCount = s + 1;
+    }
+
+    /**
+     * Appends the specified element to the end of this Vector.
+     *
+     * @param e element to be appended to this Vector
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @since 1.2
+     */
+    public synchronized boolean add(E e) {
+        modCount++;
+        add(e, elementData, elementCount);
+        return true;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this Vector
+     * If the Vector does not contain the element, it is unchanged.  More
+     * formally, removes the element with the lowest index i such that
+     * {@code Objects.equals(o, get(i))} (if such
+     * an element exists).
+     *
+     * @param o element to be removed from this Vector, if present
+     * @return true if the Vector contained the specified element
+     * @since 1.2
+     */
+    public boolean remove(Object o) {
+        return removeElement(o);
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this Vector.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @since 1.2
+     */
+    public void add(int index, E element) {
+        insertElementAt(element, index);
+    }
+
+    /**
+     * Removes the element at the specified position in this Vector.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the Vector.
+     *
+     * @param index the index of the element to be removed
+     * @return element that was removed
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E remove(int index) {
+        modCount++;
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+        E oldValue = elementData(index);
+
+        int numMoved = elementCount - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--elementCount] = null; // Let gc do its work
+
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the elements from this Vector.  The Vector will
+     * be empty after this call returns (unless it throws an exception).
+     *
+     * @since 1.2
+     */
+    public void clear() {
+        removeAllElements();
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns true if this Vector contains all of the elements in the
+     * specified Collection.
+     *
+     * @param   c a collection whose elements will be tested for containment
+     *          in this Vector
+     * @return true if this Vector contains all of the elements in the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public synchronized boolean containsAll(Collection<?> c) {
+        return super.containsAll(c);
+    }
+
+    /**
+     * Appends all of the elements in the specified Collection to the end of
+     * this Vector, in the order that they are returned by the specified
+     * Collection's Iterator.  The behavior of this operation is undefined if
+     * the specified Collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified Collection is this Vector, and this Vector is nonempty.)
+     *
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        modCount++;
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+        synchronized (this) {
+            Object[] elementData = this.elementData;
+            final int s = elementCount;
+            if (numNew > elementData.length - s)
+                elementData = grow(s + numNew);
+            System.arraycopy(a, 0, elementData, s, numNew);
+            elementCount = s + numNew;
+            return true;
+        }
+    }
+
+    /**
+     * Removes from this Vector all of its elements that are contained in the
+     * specified Collection.
+     *
+     * @param c a collection of elements to be removed from the Vector
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * Retains only the elements in this Vector that are contained in the
+     * specified Collection.  In other words, removes from this Vector all
+     * of its elements that are not contained in the specified Collection.
+     *
+     * @param c a collection of elements to be retained in this Vector
+     *          (all other elements are removed)
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private synchronized boolean bulkRemove(Predicate<? super E> filter) {
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int end = elementCount;
+        int i;
+        // Optimize for initial run of survivors
+        for (i = 0; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            for (i = elementCount = w; i < end; i++)
+                es[i] = null;
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
+    }
+
+    /**
+     * Inserts all of the elements in the specified Collection into this
+     * Vector at the specified position.  Shifts the element currently at
+     * that position (if any) and any subsequent elements to the right
+     * (increases their indices).  The new elements will appear in the Vector
+     * in the order that they are returned by the specified Collection's
+     * iterator.
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean addAll(int index, Collection<? extends E> c) {
+        if (index < 0 || index > elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        Object[] a = c.toArray();
+        modCount++;
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+        Object[] elementData = this.elementData;
+        final int s = elementCount;
+        if (numNew > elementData.length - s)
+            elementData = grow(s + numNew);
+
+        int numMoved = s - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index,
+                             elementData, index + numNew,
+                             numMoved);
+        System.arraycopy(a, 0, elementData, index, numNew);
+        elementCount = s + numNew;
+        return true;
+    }
+
+    /**
+     * Compares the specified Object with this Vector for equality.  Returns
+     * true if and only if the specified Object is also a List, both Lists
+     * have the same size, and all corresponding pairs of elements in the two
+     * Lists are <em>equal</em>.  (Two elements {@code e1} and
+     * {@code e2} are <em>equal</em> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two Lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @param o the Object to be compared for equality with this Vector
+     * @return true if the specified Object is equal to this Vector
+     */
+    public synchronized boolean equals(Object o) {
+        return super.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Vector.
+     */
+    public synchronized int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Returns a string representation of this Vector, containing
+     * the String representation of each element.
+     */
+    public synchronized String toString() {
+        return super.toString();
+    }
+
+    /**
+     * Returns a view of the portion of this List between fromIndex,
+     * inclusive, and toIndex, exclusive.  (If fromIndex and toIndex are
+     * equal, the returned List is empty.)  The returned List is backed by this
+     * List, so changes in the returned List are reflected in this List, and
+     * vice-versa.  The returned List supports all of the optional List
+     * operations supported by this List.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a List can be used as a range operation by operating on a subList view
+     * instead of a whole List.  For example, the following idiom
+     * removes a range of elements from a List:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for indexOf and lastIndexOf,
+     * and all of the algorithms in the Collections class can be applied to
+     * a subList.
+     *
+     * <p>The semantics of the List returned by this method become undefined if
+     * the backing list (i.e., this List) is <i>structurally modified</i> in
+     * any way other than via the returned List.  (Structural modifications are
+     * those that change the size of the List, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this List
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public synchronized List<E> subList(int fromIndex, int toIndex) {
+        return Collections.synchronizedList(super.subList(fromIndex, toIndex),
+                                            this);
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     */
+    protected synchronized void removeRange(int fromIndex, int toIndex) {
+        // BEGIN Android-added: make check explicit and independent of the way elementData
+        // array management is done.
+        if (fromIndex > toIndex) {
+            throw new IndexOutOfBoundsException(
+                    "From Index: " + fromIndex + " > To Index: " + toIndex);
+        }
+        // END Android-added: make check explicit and independent of the way elementData
+        // array management is done.
+        modCount++;
+        shiftTailOverGap(elementData, fromIndex, toIndex);
+    }
+
+    /** Erases the gap from lo to hi, by sliding down following elements. */
+    private void shiftTailOverGap(Object[] es, int lo, int hi) {
+        System.arraycopy(es, hi, es, lo, elementCount - hi);
+        for (int to = elementCount, i = (elementCount -= hi - lo); i < to; i++)
+            es[i] = null;
+    }
+
+    /**
+     * Loads a {@code Vector} instance from a stream
+     * (that is, deserializes it).
+     * This method performs checks to ensure the consistency
+     * of the fields.
+     *
+     * @param in the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @throws ClassNotFoundException if the stream contains data
+     *         of a non-existing class
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream in)
+            throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField gfields = in.readFields();
+        int count = gfields.get("elementCount", 0);
+        Object[] data = (Object[])gfields.get("elementData", null);
+        if (count < 0 || data == null || count > data.length) {
+            throw new StreamCorruptedException("Inconsistent vector internals");
+        }
+        elementCount = count;
+        elementData = data.clone();
+    }
+
+    /**
+     * Saves the state of the {@code Vector} instance to a stream
+     * (that is, serializes it).
+     * This method performs synchronization to ensure the consistency
+     * of the serialized data.
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @java.io.Serial
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        final java.io.ObjectOutputStream.PutField fields = s.putFields();
+        final Object[] data;
+        synchronized (this) {
+            fields.put("capacityIncrement", capacityIncrement);
+            fields.put("elementCount", elementCount);
+            data = elementData.clone();
+        }
+        fields.put("elementData", data);
+        s.writeFields();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public synchronized ListIterator<E> listIterator(int index) {
+        if (index < 0 || index > elementCount)
+            throw new IndexOutOfBoundsException("Index: "+index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public synchronized ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public synchronized Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-added: Change CME behavior: Use added limit field, not elementCount.
+        // http://b/27430229 AOSP commit 6e5b758a4438d2c154dd11a5c04d14a5d2fc907c
+        //
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = Vector.this.elementCount;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+            // return cursor != elementCount;
+            return cursor < limit;
+        }
+
+        public E next() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor;
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // if (i >= elementCount)
+                if (i >= limit)
+                    throw new NoSuchElementException();
+                cursor = i + 1;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void remove() {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.remove(lastRet);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit--;
+            }
+            cursor = lastRet;
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            synchronized (Vector.this) {
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // final int size = elementCount;
+                final int size = limit;
+                int i = cursor;
+                if (i >= size) {
+                    return;
+                }
+                final Object[] es = elementData;
+                if (i >= es.length)
+                    throw new ConcurrentModificationException();
+                while (i < size && modCount == expectedModCount)
+                    action.accept(elementAt(es, i++));
+                // update once at end of iteration to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    final class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        public E previous() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor - 1;
+                if (i < 0)
+                    throw new NoSuchElementException();
+                cursor = i;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void set(E e) {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.set(lastRet, e);
+            }
+        }
+
+        public void add(E e) {
+            int i = cursor;
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.add(i, e);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit++;
+            }
+            cursor = i + 1;
+            lastRet = -1;
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public synchronized void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int size = elementCount;
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public synchronized void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int size = elementCount;
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+        // TODO(8203662): remove increment of modCount from ...
+        modCount++;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, elementCount, c);
+        if (modCount != expectedModCount)
+            throw new ConcurrentModificationException();
+        modCount++;
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new VectorSpliterator(null, 0, -1, 0);
+    }
+
+    /** Similar to ArrayList Spliterator */
+    final class VectorSpliterator implements Spliterator<E> {
+        private Object[] array;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Creates new spliterator covering the given range. */
+        VectorSpliterator(Object[] array, int origin, int fence,
+                          int expectedModCount) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                synchronized (Vector.this) {
+                    array = elementData;
+                    expectedModCount = modCount;
+                    hi = fence = elementCount;
+                }
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new VectorSpliterator(array, lo, index = mid, expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int i;
+            if (getFence() > (i = index)) {
+                index = i + 1;
+                action.accept((E)array[i]);
+                if (modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int hi = getFence();
+            final Object[] a = array;
+            int i;
+            for (i = index, index = hi; i < hi; i++)
+                action.accept((E) a[i]);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return getFence() - index;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    void checkInvariants() {
+        // assert elementCount >= 0;
+        // assert elementCount == elementData.length || elementData[elementCount] == null;
+    }
+}
diff --git a/android-35/java/util/WeakHashMap.java b/android-35/java/util/WeakHashMap.java
new file mode 100644
index 0000000..03aee09
--- /dev/null
+++ b/android-35/java/util/WeakHashMap.java
@@ -0,0 +1,1340 @@
+/*
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+
+/**
+ * Hash table based implementation of the {@code Map} interface, with
+ * <em>weak keys</em>.
+ * An entry in a {@code WeakHashMap} will automatically be removed when
+ * its key is no longer in ordinary use.  More precisely, the presence of a
+ * mapping for a given key will not prevent the key from being discarded by the
+ * garbage collector, that is, made finalizable, finalized, and then reclaimed.
+ * When a key has been discarded its entry is effectively removed from the map,
+ * so this class behaves somewhat differently from other {@code Map}
+ * implementations.
+ *
+ * <p> Both null values and the null key are supported. This class has
+ * performance characteristics similar to those of the {@code HashMap}
+ * class, and has the same efficiency parameters of <em>initial capacity</em>
+ * and <em>load factor</em>.
+ *
+ * <p> Like most collection classes, this class is not synchronized.
+ * A synchronized {@code WeakHashMap} may be constructed using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.
+ *
+ * <p> This class is intended primarily for use with key objects whose
+ * {@code equals} methods test for object identity using the
+ * {@code ==} operator.  Once such a key is discarded it can never be
+ * recreated, so it is impossible to do a lookup of that key in a
+ * {@code WeakHashMap} at some later time and be surprised that its entry
+ * has been removed.  This class will work perfectly well with key objects
+ * whose {@code equals} methods are not based upon object identity, such
+ * as {@code String} instances.  With such recreatable key objects,
+ * however, the automatic removal of {@code WeakHashMap} entries whose
+ * keys have been discarded may prove to be confusing.
+ *
+ * <p> The behavior of the {@code WeakHashMap} class depends in part upon
+ * the actions of the garbage collector, so several familiar (though not
+ * required) {@code Map} invariants do not hold for this class.  Because
+ * the garbage collector may discard keys at any time, a
+ * {@code WeakHashMap} may behave as though an unknown thread is silently
+ * removing entries.  In particular, even if you synchronize on a
+ * {@code WeakHashMap} instance and invoke none of its mutator methods, it
+ * is possible for the {@code size} method to return smaller values over
+ * time, for the {@code isEmpty} method to return {@code false} and
+ * then {@code true}, for the {@code containsKey} method to return
+ * {@code true} and later {@code false} for a given key, for the
+ * {@code get} method to return a value for a given key but later return
+ * {@code null}, for the {@code put} method to return
+ * {@code null} and the {@code remove} method to return
+ * {@code false} for a key that previously appeared to be in the map, and
+ * for successive examinations of the key set, the value collection, and
+ * the entry set to yield successively smaller numbers of elements.
+ *
+ * <p> Each key object in a {@code WeakHashMap} is stored indirectly as
+ * the referent of a weak reference.  Therefore a key will automatically be
+ * removed only after the weak references to it, both inside and outside of the
+ * map, have been cleared by the garbage collector.
+ *
+ * <p> <strong>Implementation note:</strong> The value objects in a
+ * {@code WeakHashMap} are held by ordinary strong references.  Thus care
+ * should be taken to ensure that value objects do not strongly refer to their
+ * own keys, either directly or indirectly, since that will prevent the keys
+ * from being discarded.  Note that a value object may refer indirectly to its
+ * key via the {@code WeakHashMap} itself; that is, a value object may
+ * strongly refer to some other key object whose associated value object, in
+ * turn, strongly refers to the key of the first value object.  If the values
+ * in the map do not rely on the map holding strong references to them, one way
+ * to deal with this is to wrap values themselves within
+ * {@code WeakReferences} before
+ * inserting, as in: {@code m.put(key, new WeakReference(value))},
+ * and then unwrapping upon each {@code get}.
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <i>fail-fast</i>: if the map is structurally modified at any time after the
+ * iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author      Doug Lea
+ * @author      Josh Bloch
+ * @author      Mark Reinhold
+ * @since       1.2
+ * @see         java.util.HashMap
+ * @see         java.lang.ref.WeakReference
+ */
+public class WeakHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V> {
+
+    /**
+     * The default initial capacity -- MUST be a power of two.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    Entry<K,V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this weak hash map.
+     */
+    private int size;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hash table.
+     */
+    private final float loadFactor;
+
+    /**
+     * Reference queue for cleared WeakEntries
+     */
+    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+
+    /**
+     * The number of times this WeakHashMap has been structurally modified.
+     * Structural modifications are those that change the number of
+     * mappings in the map or otherwise modify its internal structure
+     * (e.g., rehash).  This field is used to make iterators on
+     * Collection-views of the map fail-fast.
+     *
+     * @see ConcurrentModificationException
+     */
+    int modCount;
+
+    @SuppressWarnings("unchecked")
+    private Entry<K,V>[] newTable(int n) {
+        return (Entry<K,V>[]) new Entry<?,?>[n];
+    }
+
+    /**
+     * Constructs a new, empty {@code WeakHashMap} with the given initial
+     * capacity and the given load factor.
+     *
+     * @param  initialCapacity The initial capacity of the {@code WeakHashMap}
+     * @param  loadFactor      The load factor of the {@code WeakHashMap}
+     * @throws IllegalArgumentException if the initial capacity is negative,
+     *         or if the load factor is nonpositive.
+     */
+    public WeakHashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Initial Capacity: "+
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load factor: "+
+                                               loadFactor);
+        int capacity = 1;
+        while (capacity < initialCapacity)
+            capacity <<= 1;
+        table = newTable(capacity);
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty {@code WeakHashMap} with the given initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity The initial capacity of the {@code WeakHashMap}
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public WeakHashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new, empty {@code WeakHashMap} with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public WeakHashMap() {
+        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new {@code WeakHashMap} with the same mappings as the
+     * specified map.  The {@code WeakHashMap} is created with the default
+     * load factor (0.75) and an initial capacity sufficient to hold the
+     * mappings in the specified map.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     * @since   1.3
+     */
+    public WeakHashMap(Map<? extends K, ? extends V> m) {
+        this(Math.max((int) ((float)m.size() / DEFAULT_LOAD_FACTOR + 1.0F),
+                DEFAULT_INITIAL_CAPACITY),
+             DEFAULT_LOAD_FACTOR);
+        putAll(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    private static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null) ? NULL_KEY : key;
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static Object unmaskNull(Object key) {
+        return (key == NULL_KEY) ? null : key;
+    }
+
+    /**
+     * Checks for equality of non-null reference x and possibly-null y.  By
+     * default uses Object.equals.
+     */
+    private boolean matchesKey(Entry<K,V> e, Object key) {
+        // check if the given entry refers to the given key without
+        // keeping a strong reference to the entry's referent
+        if (e.refersTo(key)) return true;
+
+        // then check for equality if the referent is not cleared
+        Object k = e.get();
+        return k != null && key.equals(k);
+    }
+
+    /**
+     * Retrieve object hash code and applies a supplemental hash function to the
+     * result hash, which defends against poor quality hash functions.  This is
+     * critical because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    final int hash(Object k) {
+        int h = k.hashCode();
+
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Returns index for hash code h.
+     */
+    private static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+
+    /**
+     * Expunges stale entries from the table.
+     */
+    private void expungeStaleEntries() {
+        for (Object x; (x = queue.poll()) != null; ) {
+            synchronized (queue) {
+                @SuppressWarnings("unchecked")
+                    Entry<K,V> e = (Entry<K,V>) x;
+                int i = indexFor(e.hash, table.length);
+
+                Entry<K,V> prev = table[i];
+                Entry<K,V> p = prev;
+                while (p != null) {
+                    Entry<K,V> next = p.next;
+                    if (p == e) {
+                        if (prev == e)
+                            table[i] = next;
+                        else
+                            prev.next = next;
+                        // Must not null out e.next;
+                        // stale entries may be in use by a HashIterator
+                        e.value = null; // Help GC
+                        size--;
+                        break;
+                    }
+                    prev = p;
+                    p = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the table after first expunging stale entries.
+     */
+    private Entry<K,V>[] getTable() {
+        expungeStaleEntries();
+        return table;
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public int size() {
+        if (size == 0)
+            return 0;
+        expungeStaleEntries();
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that
+     * {@code Objects.equals(key, k)},
+     * then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null) {
+            if (e.hash == h && matchesKey(e, k))
+                return e.value;
+            e = e.next;
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the
+     * specified key.
+     *
+     * @param  key   The key whose presence in this map is to be tested
+     * @return {@code true} if there is a mapping for {@code key};
+     *         {@code false} otherwise
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in this map.
+     * Returns null if the map contains no mapping for this key.
+     */
+    Entry<K,V> getEntry(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null && !(e.hash == h && matchesKey(e, k)))
+            e = e.next;
+        return e;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     */
+    public V put(K key, V value) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+
+        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
+            if (h == e.hash && matchesKey(e, k)) {
+                V oldValue = e.value;
+                if (value != oldValue)
+                    e.value = value;
+                return oldValue;
+            }
+        }
+
+        modCount++;
+        Entry<K,V> e = tab[i];
+        tab[i] = new Entry<>(k, value, queue, h, e);
+        if (++size >= threshold)
+            resize(tab.length * 2);
+        return null;
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        Entry<K,V>[] oldTable = getTable();
+        int oldCapacity = oldTable.length;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        Entry<K,V>[] newTable = newTable(newCapacity);
+        transfer(oldTable, newTable);
+        table = newTable;
+
+        /*
+         * If ignoring null elements and processing ref queue caused massive
+         * shrinkage, then restore old table.  This should be rare, but avoids
+         * unbounded expansion of garbage-filled tables.
+         */
+        if (size >= threshold / 2) {
+            threshold = (int)(newCapacity * loadFactor);
+        } else {
+            expungeStaleEntries();
+            transfer(newTable, oldTable);
+            table = oldTable;
+        }
+    }
+
+    /** Transfers all entries from src to dest tables */
+    private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
+        for (int j = 0; j < src.length; ++j) {
+            Entry<K,V> e = src[j];
+            src[j] = null;
+            while (e != null) {
+                Entry<K,V> next = e.next;
+                if (e.refersTo(null)) {
+                    e.next = null;  // Help GC
+                    e.value = null; //  "   "
+                    size--;
+                } else {
+                    int i = indexFor(e.hash, dest.length);
+                    e.next = dest[i];
+                    dest[i] = e;
+                }
+                e = next;
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = table.length;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > table.length)
+                resize(newCapacity);
+        }
+
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for a key from this weak hash map if it is present.
+     * More formally, if this map contains a mapping from key {@code k} to
+     * value {@code v} such that <code>(key==null ?  k==null :
+     * key.equals(k))</code>, that mapping is removed.  (The map can contain
+     * at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or {@code null} if the map contained no mapping for the key.  A
+     * return value of {@code null} does not <i>necessarily</i> indicate
+     * that the map contained no mapping for the key; it's also possible
+     * that the map explicitly mapped the key to {@code null}.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && matchesKey(e, k)) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return e.value;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return null;
+    }
+
+    /** Special version of remove needed by Entry set */
+    boolean removeMapping(Object o) {
+        if (!(o instanceof Map.Entry<?, ?> entry))
+            return false;
+        Entry<K,V>[] tab = getTable();
+        Object k = maskNull(entry.getKey());
+        int h = hash(k);
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && e.equals(entry)) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return true;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        // clear out ref queue. We don't need to expunge entries
+        // since table is getting cleared.
+        while (queue.poll() != null)
+            ;
+
+        modCount++;
+        Arrays.fill(table, null);
+        size = 0;
+
+        // Allocation of array may have caused GC, which may have caused
+        // additional entries to go stale.  Removing these entries from the
+        // reference queue will make them eligible for reclamation.
+        while (queue.poll() != null)
+            ;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        if (value==null)
+            return containsNullValue();
+
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (value.equals(e.value))
+                    return true;
+        return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     */
+    private boolean containsNullValue() {
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (e.value==null)
+                    return true;
+        return false;
+    }
+
+    /**
+     * The entries in this hash table extend WeakReference, using its main ref
+     * field as the key.
+     */
+    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
+        V value;
+        final int hash;
+        Entry<K,V> next;
+
+        /**
+         * Creates new entry.
+         */
+        Entry(Object key, V value,
+              ReferenceQueue<Object> queue,
+              int hash, Entry<K,V> next) {
+            super(key, queue);
+            this.value = value;
+            this.hash  = hash;
+            this.next  = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        public K getKey() {
+            return (K) WeakHashMap.unmaskNull(get());
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry<?, ?> e))
+                return false;
+            K k1 = getKey();
+            Object k2 = e.getKey();
+            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
+                V v1 = getValue();
+                Object v2 = e.getValue();
+                if (v1 == v2 || (v1 != null && v1.equals(v2)))
+                    return true;
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            K k = getKey();
+            V v = getValue();
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
+        }
+
+        public String toString() {
+            return getKey() + "=" + getValue();
+        }
+    }
+
+    private abstract class HashIterator<T> implements Iterator<T> {
+        private int index;
+        private Entry<K,V> entry;
+        private Entry<K,V> lastReturned;
+        private int expectedModCount = modCount;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between hasNext and next
+         */
+        private Object nextKey;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between nextEntry() and any use of the entry
+         */
+        private Object currentKey;
+
+        HashIterator() {
+            index = isEmpty() ? 0 : table.length;
+        }
+
+        public boolean hasNext() {
+            Entry<K,V>[] t = table;
+
+            while (nextKey == null) {
+                Entry<K,V> e = entry;
+                int i = index;
+                while (e == null && i > 0)
+                    e = t[--i];
+                entry = e;
+                index = i;
+                if (e == null) {
+                    currentKey = null;
+                    return false;
+                }
+                nextKey = e.get(); // hold on to key in strong ref
+                if (nextKey == null)
+                    entry = entry.next;
+            }
+            return true;
+        }
+
+        /** The common parts of next() across different types of iterators */
+        protected Entry<K,V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (nextKey == null && !hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = entry;
+            entry = entry.next;
+            currentKey = nextKey;
+            nextKey = null;
+            return lastReturned;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            WeakHashMap.this.remove(currentKey);
+            expectedModCount = modCount;
+            lastReturned = null;
+            currentKey = null;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<V> {
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    private class KeyIterator extends HashIterator<K> {
+        public K next() {
+            return nextEntry().getKey();
+        }
+    }
+
+    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    // Views
+
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+
+        public boolean remove(Object o) {
+            if (containsKey(o)) {
+                WeakHashMap.this.remove(o);
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        return es != null ? es : (entrySet = new EntrySet());
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            return o instanceof Map.Entry<?, ?> e
+                    && getEntry(e.getKey()) != null
+                    && getEntry(e.getKey()).equals(e);
+        }
+
+        public boolean remove(Object o) {
+            return removeMapping(o);
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        private List<Map.Entry<K,V>> deepCopy() {
+            List<Map.Entry<K,V>> list = new ArrayList<>(size());
+            for (Map.Entry<K,V> e : this)
+                list.add(new AbstractMap.SimpleEntry<>(e));
+            return list;
+        }
+
+        public Object[] toArray() {
+            return deepCopy().toArray();
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return deepCopy().toArray(a);
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();;
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    /**
+     * Similar form as other hash Spliterators, but skips dead
+     * elements.
+     */
+    static class WeakHashMapSpliterator<K,V> {
+        final WeakHashMap<K,V> map;
+        WeakHashMap.Entry<K,V> current; // current node
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // for comodification checks
+
+        WeakHashMapSpliterator(WeakHashMap<K,V> m, int origin,
+                               int fence, int est,
+                               int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                WeakHashMap<K,V> m = map;
+                est = m.size();
+                expectedModCount = m.modCount;
+                hi = fence = m.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                     expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
+                                       expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null)
+                            action.accept(v);
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            action.accept(v);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return 0;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                       expectedModCount);
+        }
+
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<>(k, v));
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<>(k, v));
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/android-35/java/util/XMLUtils.java b/android-35/java/util/XMLUtils.java
new file mode 100644
index 0000000..8f061e5
--- /dev/null
+++ b/android-35/java/util/XMLUtils.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import org.w3c.dom.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+/**
+ * A class used to aid in Properties load and save in XML. Keeping this
+ * code outside of Properties helps reduce the number of classes loaded
+ * when Properties is loaded.
+ *
+ * @author  Michael McCloskey
+ * @since   1.3
+ */
+class XMLUtils {
+
+    // XML loading and saving methods for Properties
+
+    // The required DTD URI for exported properties
+    private static final String PROPS_DTD_URI =
+    "http://java.sun.com/dtd/properties.dtd";
+
+    private static final String PROPS_DTD =
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+    "<!-- DTD for properties -->"                +
+    "<!ELEMENT properties ( comment?, entry* ) >"+
+    "<!ATTLIST properties"                       +
+        " version CDATA #FIXED \"1.0\">"         +
+    "<!ELEMENT comment (#PCDATA) >"              +
+    "<!ELEMENT entry (#PCDATA) >"                +
+    "<!ATTLIST entry "                           +
+        " key CDATA #REQUIRED>";
+
+    /**
+     * Version number for the format of exported properties files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    static void load(Properties props, InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        Document doc = null;
+        try {
+            doc = getLoadingDoc(in);
+        } catch (SAXException saxe) {
+            throw new InvalidPropertiesFormatException(saxe);
+        }
+        Element propertiesElement = doc.getDocumentElement();
+        String xmlVersion = propertiesElement.getAttribute("version");
+        if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+            throw new InvalidPropertiesFormatException(
+                "Exported Properties file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You" +
+                " may need to install a newer version of JDK.");
+        importProperties(props, propertiesElement);
+    }
+
+    static Document getLoadingDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: We don't currently have a validating document builder.
+        // Revert this if the situation changes.
+        //
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            InputSource is = new InputSource(in);
+            return db.parse(is);
+        } catch (ParserConfigurationException x) {
+            throw new Error(x);
+        }
+    }
+
+    static void importProperties(Properties props, Element propertiesElement) {
+        NodeList entries = propertiesElement.getChildNodes();
+        int numEntries = entries.getLength();
+        int start = numEntries > 0 &&
+            entries.item(0).getNodeName().equals("comment") ? 1 : 0;
+        for (int i=start; i<numEntries; i++) {
+            // Android-changed: Exclude CDATA nodes and the like.
+            if (!(entries.item(i) instanceof Element)) {
+                continue;
+            }
+            Element entry = (Element)entries.item(i);
+            if (entry.hasAttribute("key")) {
+                Node n = entry.getFirstChild();
+                String val = (n == null) ? "" : n.getNodeValue();
+                props.setProperty(entry.getAttribute("key"), val);
+            }
+        }
+    }
+
+    static void save(Properties props, OutputStream os, String comment,
+                     String encoding)
+        throws IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder db = null;
+        try {
+            db = dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException pce) {
+            assert(false);
+        }
+        Document doc = db.newDocument();
+        Element properties =  (Element)
+            doc.appendChild(doc.createElement("properties"));
+
+        if (comment != null) {
+            Element comments = (Element)properties.appendChild(
+                doc.createElement("comment"));
+            comments.appendChild(doc.createTextNode(comment));
+        }
+
+        synchronized (props) {
+            for (String key : props.stringPropertyNames()) {
+                Element entry = (Element)properties.appendChild(
+                    doc.createElement("entry"));
+                entry.setAttribute("key", key);
+                entry.appendChild(doc.createTextNode(props.getProperty(key)));
+            }
+        }
+        emitDocument(doc, os, encoding);
+    }
+
+    static void emitDocument(Document doc, OutputStream os, String encoding)
+        throws IOException
+    {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer t = null;
+        try {
+            t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI);
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            t.setOutputProperty(OutputKeys.METHOD, "xml");
+            t.setOutputProperty(OutputKeys.ENCODING, encoding);
+        } catch (TransformerConfigurationException tce) {
+            assert(false);
+        }
+        DOMSource doms = new DOMSource(doc);
+        StreamResult sr = new StreamResult(os);
+        try {
+            t.transform(doms, sr);
+        } catch (TransformerException te) {
+            IOException ioe = new IOException();
+            ioe.initCause(te);
+            throw ioe;
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PROPS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PROPS_DTD));
+                is.setSystemId(PROPS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/AbstractExecutorService.java b/android-35/java/util/concurrent/AbstractExecutorService.java
new file mode 100644
index 0000000..f45c003
--- /dev/null
+++ b/android-35/java/util/concurrent/AbstractExecutorService.java
@@ -0,0 +1,315 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Provides default implementations of {@link ExecutorService}
+ * execution methods. This class implements the {@code submit},
+ * {@code invokeAny} and {@code invokeAll} methods using a
+ * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults
+ * to the {@link FutureTask} class provided in this package.  For example,
+ * the implementation of {@code submit(Runnable)} creates an
+ * associated {@code RunnableFuture} that is executed and
+ * returned. Subclasses may override the {@code newTaskFor} methods
+ * to return {@code RunnableFuture} implementations other than
+ * {@code FutureTask}.
+ *
+ * <p><b>Extension example.</b> Here is a sketch of a class
+ * that customizes {@link ThreadPoolExecutor} to use
+ * a {@code CustomTask} class instead of the default {@code FutureTask}:
+ * <pre> {@code
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableFuture<V> { ... }
+ *
+ *   protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
+ *       return new CustomTask<V>(c);
+ *   }
+ *   protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
+ *       return new CustomTask<V>(r, v);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractExecutorService implements ExecutorService {
+
+    /**
+     * Constructor for subclasses to call.
+     */
+    public AbstractExecutorService() {}
+
+    /**
+     * Returns a {@code RunnableFuture} for the given runnable and default
+     * value.
+     *
+     * @param runnable the runnable task being wrapped
+     * @param value the default value for the returned future
+     * @param <T> the type of the given value
+     * @return a {@code RunnableFuture} which, when run, will run the
+     * underlying runnable and which, as a {@code Future}, will yield
+     * the given value as its result and provide for cancellation of
+     * the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new FutureTask<T>(runnable, value);
+    }
+
+    /**
+     * Returns a {@code RunnableFuture} for the given callable task.
+     *
+     * @param callable the callable task being wrapped
+     * @param <T> the type of the callable's result
+     * @return a {@code RunnableFuture} which, when run, will call the
+     * underlying callable and which, as a {@code Future}, will yield
+     * the callable's result as its result and provide for
+     * cancellation of the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new FutureTask<T>(callable);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<Void> ftask = newTaskFor(task, null);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task, result);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * the main mechanics of invokeAny.
+     */
+    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
+                              boolean timed, long nanos)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        if (tasks == null)
+            throw new NullPointerException();
+        int ntasks = tasks.size();
+        if (ntasks == 0)
+            throw new IllegalArgumentException();
+        ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
+        ExecutorCompletionService<T> ecs =
+            new ExecutorCompletionService<T>(this);
+
+        // For efficiency, especially in executors with limited
+        // parallelism, check to see if previously submitted tasks are
+        // done before submitting more of them. This interleaving
+        // plus the exception mechanics account for messiness of main
+        // loop.
+
+        try {
+            // Record exceptions so that if we fail to obtain any
+            // result, we can throw the last exception we got.
+            ExecutionException ee = null;
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Iterator<? extends Callable<T>> it = tasks.iterator();
+
+            // Start one task for sure; the rest incrementally
+            futures.add(ecs.submit(it.next()));
+            --ntasks;
+            int active = 1;
+
+            for (;;) {
+                Future<T> f = ecs.poll();
+                if (f == null) {
+                    if (ntasks > 0) {
+                        --ntasks;
+                        futures.add(ecs.submit(it.next()));
+                        ++active;
+                    }
+                    else if (active == 0)
+                        break;
+                    else if (timed) {
+                        f = ecs.poll(nanos, NANOSECONDS);
+                        if (f == null)
+                            throw new TimeoutException();
+                        nanos = deadline - System.nanoTime();
+                    }
+                    else
+                        f = ecs.take();
+                }
+                if (f != null) {
+                    --active;
+                    try {
+                        return f.get();
+                    } catch (ExecutionException eex) {
+                        ee = eex;
+                    } catch (RuntimeException rex) {
+                        ee = new ExecutionException(rex);
+                    }
+                }
+            }
+
+            if (ee == null)
+                ee = new ExecutionException();
+            throw ee;
+
+        } finally {
+            cancelAll(futures);
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException {
+        try {
+            return doInvokeAny(tasks, false, 0);
+        } catch (TimeoutException cannotHappen) {
+            assert false;
+            return null;
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                           long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        return doInvokeAny(tasks, true, unit.toNanos(timeout));
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        try {
+            for (Callable<T> t : tasks) {
+                RunnableFuture<T> f = newTaskFor(t);
+                futures.add(f);
+                execute(f);
+            }
+            for (int i = 0, size = futures.size(); i < size; i++) {
+                Future<T> f = futures.get(i);
+                if (!f.isDone()) {
+                    try { f.get(); }
+                    catch (CancellationException | ExecutionException ignore) {}
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        final long nanos = unit.toNanos(timeout);
+        final long deadline = System.nanoTime() + nanos;
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        int j = 0;
+        timedOut: try {
+            for (Callable<T> t : tasks)
+                futures.add(newTaskFor(t));
+
+            final int size = futures.size();
+
+            // Interleave time checks and calls to execute in case
+            // executor doesn't have any/much parallelism.
+            for (int i = 0; i < size; i++) {
+                if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
+                    break timedOut;
+                execute((Runnable)futures.get(i));
+            }
+
+            for (; j < size; j++) {
+                Future<T> f = futures.get(j);
+                if (!f.isDone()) {
+                    try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
+                    catch (CancellationException | ExecutionException ignore) {}
+                    catch (TimeoutException timedOut) {
+                        break timedOut;
+                    }
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+        // Timed out before all the tasks could be completed; cancel remaining
+        cancelAll(futures, j);
+        return futures;
+    }
+
+    private static <T> void cancelAll(ArrayList<Future<T>> futures) {
+        cancelAll(futures, 0);
+    }
+
+    /** Cancels all futures with index at least j. */
+    private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
+        for (int size = futures.size(); j < size; j++)
+            futures.get(j).cancel(true);
+    }
+}
diff --git a/android-35/java/util/concurrent/ArrayBlockingQueue.java b/android-35/java/util/concurrent/ArrayBlockingQueue.java
new file mode 100644
index 0000000..1f41666
--- /dev/null
+++ b/android-35/java/util/concurrent/ArrayBlockingQueue.java
@@ -0,0 +1,1638 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.ref.WeakReference;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * A bounded {@linkplain BlockingQueue blocking queue} backed by an
+ * array.  This queue orders elements FIFO (first-in-first-out).  The
+ * <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.  The <em>tail</em> of the queue is that
+ * element that has been on the queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ *
+ * <p>This is a classic &quot;bounded buffer&quot;, in which a
+ * fixed-sized array holds elements inserted by producers and
+ * extracted by consumers.  Once created, the capacity cannot be
+ * changed.  Attempts to {@code put} an element into a full queue
+ * will result in the operation blocking; attempts to {@code take} an
+ * element from an empty queue will similarly block.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order. Fairness
+ * generally decreases throughput but reduces variability and avoids
+ * starvation.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ArrayBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+
+    /*
+     * Much of the implementation mechanics, especially the unusual
+     * nested loops, are shared and co-maintained with ArrayDeque.
+     */
+
+    /**
+     * Serialization ID. This class relies on default serialization
+     * even for the items array, which is default-serialized, even if
+     * it is empty. Otherwise it could not be declared final, which is
+     * necessary here.
+     */
+    private static final long serialVersionUID = -817911632652898426L;
+
+    /** The queued items */
+    @SuppressWarnings("serial") // Conditionally serializable
+    final Object[] items;
+
+    /** items index for next take, poll, peek or remove */
+    int takeIndex;
+
+    /** items index for next put, offer, or add */
+    int putIndex;
+
+    /** Number of elements in the queue */
+    int count;
+
+    /*
+     * Concurrency control uses the classic two-condition algorithm
+     * found in any textbook.
+     */
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock;
+
+    /** Condition for waiting takes */
+    @SuppressWarnings("serial")  // Classes implementing Condition may be serializable.
+    private final Condition notEmpty;
+
+    /** Condition for waiting puts */
+    @SuppressWarnings("serial")  // Classes implementing Condition may be serializable.
+    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;
+
+    // Internal helper methods
+
+    /**
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
+    }
+
+    /**
+     * Returns item at index i.
+     */
+    @SuppressWarnings("unchecked")
+    final E itemAt(int i) {
+        return (E) items[i];
+    }
+
+    /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static <E> E itemAt(Object[] items, int i) {
+        return (E) items[i];
+    }
+
+    /**
+     * Inserts element at current put position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private void enqueue(E e) {
+        // assert lock.isHeldByCurrentThread();
+        // assert lock.getHoldCount() == 1;
+        // assert items[putIndex] == null;
+        final Object[] items = this.items;
+        items[putIndex] = e;
+        if (++putIndex == items.length) putIndex = 0;
+        count++;
+        notEmpty.signal();
+    }
+
+    /**
+     * Extracts element at current take position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private E dequeue() {
+        // assert lock.isHeldByCurrentThread();
+        // assert lock.getHoldCount() == 1;
+        // assert items[takeIndex] != null;
+        final Object[] items = this.items;
+        @SuppressWarnings("unchecked")
+        E e = (E) items[takeIndex];
+        items[takeIndex] = null;
+        if (++takeIndex == items.length) takeIndex = 0;
+        count--;
+        if (itrs != null)
+            itrs.elementDequeued();
+        notFull.signal();
+        return e;
+    }
+
+    /**
+     * Deletes item at array index removeIndex.
+     * Utility for remove(Object) and iterator.remove.
+     * Call only when holding lock.
+     */
+    void removeAt(final int removeIndex) {
+        // assert lock.isHeldByCurrentThread();
+        // assert lock.getHoldCount() == 1;
+        // assert items[removeIndex] != null;
+        // assert removeIndex >= 0 && removeIndex < items.length;
+        final Object[] items = this.items;
+        if (removeIndex == takeIndex) {
+            // removing front item; just advance
+            items[takeIndex] = null;
+            if (++takeIndex == items.length) takeIndex = 0;
+            count--;
+            if (itrs != null)
+                itrs.elementDequeued();
+        } else {
+            // an "interior" remove
+
+            // slide over all others up through putIndex.
+            for (int i = removeIndex, putIndex = this.putIndex;;) {
+                int pred = i;
+                if (++i == items.length) i = 0;
+                if (i == putIndex) {
+                    items[pred] = null;
+                    this.putIndex = pred;
+                    break;
+                }
+                items[pred] = items[i];
+            }
+            count--;
+            if (itrs != null)
+                itrs.removedAt(removeIndex);
+        }
+        notFull.signal();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and default access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity) {
+        this(capacity, false);
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and the specified access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair) {
+        if (capacity <= 0)
+            throw new IllegalArgumentException();
+        this.items = new Object[capacity];
+        lock = new ReentrantLock(fair);
+        notEmpty = lock.newCondition();
+        notFull =  lock.newCondition();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity, the specified access policy and initially containing the
+     * elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @param c the collection of elements to initially contain
+     * @throws IllegalArgumentException if {@code capacity} is less than
+     *         {@code c.size()}, or less than 1.
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair,
+                              Collection<? extends E> c) {
+        this(capacity, fair);
+
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Lock only for visibility, not mutual exclusion
+        try {
+            final Object[] items = this.items;
+            int i = 0;
+            try {
+                for (E e : c)
+                    items[i++] = Objects.requireNonNull(e);
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new IllegalArgumentException();
+            }
+            count = i;
+            putIndex = (i == capacity) ? 0 : i;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and throwing an
+     * {@code IllegalStateException} if this queue is full.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if this queue is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return super.add(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.  This method is generally preferable to method {@link #add},
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count == items.length)
+                return false;
+            else {
+                enqueue(e);
+                return true;
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * for space to become available if the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length)
+                notFull.await();
+            enqueue(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * up to the specified wait time for space to become available if
+     * the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        Objects.requireNonNull(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(e);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (count == 0) ? null : dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0)
+                notEmpty.await();
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return itemAt(takeIndex); // null when queue is empty
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.length - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 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).
+     *
+     * <p>Removal of interior elements in circular array based queues
+     * is an intrinsically slow and disruptive operation, so should
+     * be undertaken only in exceptional circumstances, ideally
+     * only when the queue is known not to be accessible by other
+     * threads.
+     *
+     * @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) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i])) {
+                            removeAt(i);
+                            return true;
+                        }
+                    if (to == end) break;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 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;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i]))
+                            return true;
+                    if (to == end) break;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int end = takeIndex + count;
+            final Object[] a = Arrays.copyOfRange(items, takeIndex, end);
+            if (end != putIndex)
+                System.arraycopy(items, 0, a, items.length - takeIndex, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int count = this.count;
+            final int firstLeg = Math.min(items.length - takeIndex, count);
+            if (a.length < count) {
+                a = (T[]) Arrays.copyOfRange(items, takeIndex, takeIndex + count,
+                                             a.getClass());
+            } else {
+                System.arraycopy(items, takeIndex, a, 0, firstLeg);
+                if (a.length > count)
+                    a[count] = null;
+            }
+            if (firstLeg < count)
+                System.arraycopy(items, 0, a, firstLeg, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int k;
+            if ((k = count) > 0) {
+                circularClear(items, takeIndex, putIndex);
+                takeIndex = putIndex;
+                count = 0;
+                if (itrs != null)
+                    itrs.queueIsEmpty();
+                for (; k > 0 && lock.hasWaiters(notFull); k--)
+                    notFull.signal();
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Nulls out slots starting at array index i, upto index end.
+     * Condition i == end means "full" - the entire array is cleared.
+     */
+    private static void circularClear(Object[] items, int i, int end) {
+        // assert 0 <= i && i < items.length;
+        // assert 0 <= end && end < items.length;
+        for (int to = (i < end) ? end : items.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++) items[i] = null;
+            if (to == end) break;
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final Object[] items = this.items;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            int take = takeIndex;
+            int i = 0;
+            try {
+                while (i < n) {
+                    @SuppressWarnings("unchecked")
+                    E e = (E) items[take];
+                    c.add(e);
+                    items[take] = null;
+                    if (++take == items.length) take = 0;
+                    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();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 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 href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * 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.
+     */
+    class Itrs {
+
+        /**
+         * 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;
+            }
+        }
+
+        /** Incremented whenever takeIndex wraps around to 0 */
+        int cycles;
+
+        /** Linked list of weak iterator references */
+        private Node head;
+
+        /** Used to expunge stale iterators */
+        private Node sweeper;
+
+        private static final int SHORT_SWEEP_PROBES = 4;
+        private static final int LONG_SWEEP_PROBES = 16;
+
+        Itrs(Itr initial) {
+            register(initial);
+        }
+
+        /**
+         * 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.isHeldByCurrentThread();
+            // 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;
+                }
+                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;
+        }
+
+        /**
+         * Adds a new iterator to the linked list of tracked iterators.
+         */
+        void register(Itr itr) {
+            // assert lock.isHeldByCurrentThread();
+            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.isHeldByCurrentThread();
+            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;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occurred.
+         *
+         * 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.isHeldByCurrentThread();
+            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.isHeldByCurrentThread();
+            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.
+     *
+     * Method forEachRemaining, added in Java 8, is treated similarly
+     * to hasNext returning false, in that we switch to detached mode,
+     * but we regard it as an even stronger request to "close" this
+     * iteration, and don't bother supporting subsequent remove().
+     */
+    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() {
+            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.isHeldByCurrentThread();
+            return prevTakeIndex < 0;
+        }
+
+        private int incCursor(int index) {
+            // assert lock.isHeldByCurrentThread();
+            if (++index == items.length) index = 0;
+            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.isHeldByCurrentThread();
+            // 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 = (long) (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.isHeldByCurrentThread();
+            // 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() {
+            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() {
+            final E e = nextItem;
+            if (e == 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;
+                    if (lastRet == REMOVED) detach();
+                }
+            } finally {
+                lock.unlock();
+            }
+            return e;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                final E e = nextItem;
+                if (e == null) return;
+                if (!isDetached())
+                    incorporateDequeues();
+                action.accept(e);
+                if (isDetached() || cursor < 0) return;
+                final Object[] items = ArrayBlockingQueue.this.items;
+                for (int i = cursor, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            } finally {
+                // Calling forEachRemaining is a strong hint that this
+                // iteration is surely over; supporting remove() after
+                // forEachRemaining() is more trouble than it's worth
+                cursor = nextIndex = lastRet = NONE;
+                nextItem = lastItem = null;
+                detach();
+                lock.unlock();
+            }
+        }
+
+        public void remove() {
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            // assert lock.getHoldCount() == 1;
+            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.isHeldByCurrentThread();
+            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) occurred.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean removedAt(int removedIndex) {
+            // assert lock.isHeldByCurrentThread();
+            if (isDetached())
+                return true;
+
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevTakeIndex = this.prevTakeIndex;
+            final int len = items.length;
+            // distance from prevTakeIndex to removedIndex
+            final int removedDistance =
+                len * (itrs.cycles - this.prevCycles
+                       + ((removedIndex < takeIndex) ? 1 : 0))
+                + (removedIndex - prevTakeIndex);
+            // assert itrs.cycles - this.prevCycles >= 0;
+            // assert itrs.cycles - this.prevCycles <= 1;
+            // assert removedDistance > 0;
+            // assert removedIndex != takeIndex;
+            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, len);
+                }
+            }
+            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, len);
+            }
+            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, len);
+            }
+            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.isHeldByCurrentThread();
+            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());
+//         }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (this, (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (itrs == null) { // check for active iterators
+                if (count > 0) {
+                    final Object[] items = this.items;
+                    // Optimize for initial run of survivors
+                    for (int i = takeIndex, end = putIndex,
+                             to = (i < end) ? end : items.length;
+                         ; i = 0, to = end) {
+                        for (; i < to; i++)
+                            if (filter.test(itemAt(items, i)))
+                                return bulkRemoveModified(filter, i);
+                        if (to == end) break;
+                    }
+                }
+                return false;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Active iterators are too hairy!
+        // Punting (for now) to the slow n^2 algorithm ...
+        return super.removeIf(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Returns circular distance from i to j, disambiguating i == j to
+     * items.length; never returns 0.
+     */
+    private int distanceNonEmpty(int i, int j) {
+        if ((j -= i) <= 0) j += items.length;
+        return j;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but not write), so traverse once to find elements to
+     * delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = items;
+        final int capacity = items.length;
+        final int end = putIndex;
+        final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(itemAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        count -= distanceNonEmpty(w, end);
+        circularClear(es, putIndex = w, end);
+        return true;
+    }
+
+    /** debugging */
+    void checkInvariants() {
+        // meta-assertions
+        // assert lock.isHeldByCurrentThread();
+        if (!invariantsSatisfied()) {
+            String detail = String.format(
+                "takeIndex=%d putIndex=%d count=%d capacity=%d items=%s",
+                takeIndex, putIndex, count, items.length,
+                Arrays.toString(items));
+            System.err.println(detail);
+            throw new AssertionError(detail);
+        }
+    }
+
+    private boolean invariantsSatisfied() {
+        // Unlike ArrayDeque, we have a count field but no spare slot.
+        // We prefer ArrayDeque's strategy (and the names of its fields!),
+        // but our field layout is baked into the serial form, and so is
+        // too annoying to change.
+        //
+        // putIndex == takeIndex must be disambiguated by checking count.
+        int capacity = items.length;
+        return capacity > 0
+            && items.getClass() == Object[].class
+            && (takeIndex | putIndex | count) >= 0
+            && takeIndex <  capacity
+            && putIndex  <  capacity
+            && count     <= capacity
+            && (putIndex - takeIndex - count) % capacity == 0
+            && (count == 0 || items[takeIndex] != null)
+            && (count == capacity || items[putIndex] == null)
+            && (count == 0 || items[dec(putIndex, capacity)] != null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     *
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.InvalidObjectException if invariants are violated
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in items array and various fields
+        s.defaultReadObject();
+
+        if (!invariantsSatisfied())
+            throw new java.io.InvalidObjectException("invariants violated");
+    }
+}
diff --git a/android-35/java/util/concurrent/BlockingDeque.java b/android-35/java/util/concurrent/BlockingDeque.java
new file mode 100644
index 0000000..8043510
--- /dev/null
+++ b/android-35/java/util/concurrent/BlockingDeque.java
@@ -0,0 +1,649 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A {@link Deque} that additionally supports blocking operations that wait
+ * for the deque to become non-empty when retrieving an element, and wait for
+ * space to become available in the deque when storing an element.
+ *
+ * <p>{@code BlockingDeque} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table class="plain">
+ * <caption>Summary of BlockingDeque methods</caption>
+ *  <tr>
+ *    <th id="First" colspan="5"> First Element (Head)</th>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <th id="FThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ *    <th id="FValue" style="font-weight:normal; font-style: italic">Special value</th>
+ *    <th id="FBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ *    <th id="FTimes" style="font-weight:normal; font-style: italic">Times out</th>
+ *  </tr>
+ *  <tr>
+ *    <th id="FInsert" style="text-align:left">Insert</th>
+ *    <td headers="First FInsert FThrow">{@link #addFirst(Object) addFirst(e)}</td>
+ *    <td headers="First FInsert FValue">{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td headers="First FInsert FBlock">{@link #putFirst(Object) putFirst(e)}</td>
+ *    <td headers="First FInsert FTimes">{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="FRemove" style="text-align:left">Remove</th>
+ *    <td headers="First FRemove FThrow">{@link #removeFirst() removeFirst()}</td>
+ *    <td headers="First FRemove FValue">{@link #pollFirst() pollFirst()}</td>
+ *    <td headers="First FRemove FBlock">{@link #takeFirst() takeFirst()}</td>
+ *    <td headers="First FRemove FTimes">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="FExamine" style="text-align:left">Examine</th>
+ *    <td headers="First FExamine FThrow">{@link #getFirst() getFirst()}</td>
+ *    <td headers="First FExamine FValue">{@link #peekFirst() peekFirst()}</td>
+ *    <td headers="First FExamine FBlock" style="font-style:italic">not applicable</td>
+ *    <td headers="First FExamine FTimes" style="font-style:italic">not applicable</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="Last" colspan="5"> Last Element (Tail)</th>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <th id="LThrow" style="font-weight:normal; font-style: italic">Throws exception</th>
+ *    <th id="LValue" style="font-weight:normal; font-style: italic">Special value</th>
+ *    <th id="LBlock" style="font-weight:normal; font-style: italic">Blocks</th>
+ *    <th id="LTimes" style="font-weight:normal; font-style: italic">Times out</th>
+ *  </tr>
+ *  <tr>
+ *    <th id="LInsert" style="text-align:left">Insert</th>
+ *    <td headers="Last LInsert LThrow">{@link #addLast(Object) addLast(e)}</td>
+ *    <td headers="Last LInsert LValue">{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td headers="Last LInsert LBlock">{@link #putLast(Object) putLast(e)}</td>
+ *    <td headers="Last LInsert LTimes">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="LRemove" style="text-align:left">Remove</th>
+ *    <td headers="Last LRemove LThrow">{@link #removeLast() removeLast()}</td>
+ *    <td headers="Last LRemove LValue">{@link #pollLast() pollLast()}</td>
+ *    <td headers="Last LRemove LBlock">{@link #takeLast() takeLast()}</td>
+ *    <td headers="Last LRemove LTimes">{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="LExamine" style="text-align:left">Examine</th>
+ *    <td headers="Last LExamine LThrow">{@link #getLast() getLast()}</td>
+ *    <td headers="Last LExamine LValue">{@link #peekLast() peekLast()}</td>
+ *    <td headers="Last LExamine LBlock" style="font-style:italic">not applicable</td>
+ *    <td headers="Last LExamine LTimes" style="font-style:italic">not applicable</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Like any {@link BlockingQueue}, a {@code BlockingDeque} is thread safe,
+ * does not permit null elements, and may (or may not) be
+ * capacity-constrained.
+ *
+ * <p>A {@code BlockingDeque} implementation may be used directly as a FIFO
+ * {@code BlockingQueue}. The methods inherited from the
+ * {@code BlockingQueue} interface are precisely equivalent to
+ * {@code BlockingDeque} methods as indicated in the following table:
+ *
+ * <table class="plain">
+ * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <th id="BQueue"> {@code BlockingQueue} Method</th>
+ *    <th id="BDeque"> Equivalent {@code BlockingDeque} Method</th>
+ *  </tr>
+ *  <tr>
+ *    <th id="Insert" rowspan="4" style="text-align:left; vertical-align:top">Insert</th>
+ *    <th id="add" style="font-weight:normal; text-align:left">{@link #add(Object) add(e)}</th>
+ *    <td headers="Insert BDeque add">{@link #addLast(Object) addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="offer1" style="font-weight:normal; text-align:left">{@link #offer(Object) offer(e)}</th>
+ *    <td headers="Insert BDeque offer1">{@link #offerLast(Object) offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="put" style="font-weight:normal; text-align:left">{@link #put(Object) put(e)}</th>
+ *    <td headers="Insert BDeque put">{@link #putLast(Object) putLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="offer2" style="font-weight:normal; text-align:left">{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</th>
+ *    <td headers="Insert BDeque offer2">{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="Remove" rowspan="4" style="text-align:left; vertical-align:top">Remove</th>
+ *    <th id="remove" style="font-weight:normal; text-align:left">{@link #remove() remove()}</th>
+ *    <td headers="Remove BDeque remove">{@link #removeFirst() removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="poll1" style="font-weight:normal; text-align:left">{@link #poll() poll()}</th>
+ *    <td headers="Remove BDeque poll1">{@link #pollFirst() pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="take" style="font-weight:normal; text-align:left">{@link #take() take()}</th>
+ *    <td headers="Remove BDeque take">{@link #takeFirst() takeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="poll2" style="font-weight:normal; text-align:left">{@link #poll(long, TimeUnit) poll(time, unit)}</th>
+ *    <td headers="Remove BDeque poll2">{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="Examine" rowspan="2" style="text-align:left; vertical-align:top">Examine</th>
+ *    <th id="element" style="font-weight:normal; text-align:left">{@link #element() element()}</th>
+ *    <td headers="Examine BDeque element">{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <th id="peek" style="font-weight:normal; text-align:left">{@link #peek() peek()}</th>
+ *    <td headers="Examine BDeque peek">{@link #peekFirst() peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingDeque} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
+    /*
+     * We have "diamond" multiple interface inheritance here, and that
+     * introduces ambiguities.  Methods might end up with different
+     * specs depending on the branch chosen by javadoc.  Thus a lot of
+     * methods specs here are copied from superinterfaces.
+     */
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerFirst(Object) offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerLast(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * 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
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * 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
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putFirst(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putLast(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @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 space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @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 space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeFirst() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the tail of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeLast() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @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 head of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @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 tail of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} 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
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} 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
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** BlockingQueue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast(Object) addLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * 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(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (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(Object) putLast}.
+     *
+     * @param e the element to add
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque), waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #offerLast(Object,long,TimeUnit) offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll() poll()} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting if
+     * necessary until an element becomes available.
+     *
+     * <p>This method is equivalent to {@link #takeFirst() takeFirst}.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #pollFirst(long,TimeUnit) pollFirst}.
+     *
+     * @return the head of this deque, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek() peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst() peekFirst}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peek();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
+     *
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void push(E e);
+}
diff --git a/android-35/java/util/concurrent/BlockingQueue.java b/android-35/java/util/concurrent/BlockingQueue.java
new file mode 100644
index 0000000..ec7593d
--- /dev/null
+++ b/android-35/java/util/concurrent/BlockingQueue.java
@@ -0,0 +1,375 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.Queue;
+
+/**
+ * A {@link Queue} that additionally supports operations that wait for
+ * the queue to become non-empty when retrieving an element, and wait
+ * for space to become available in the queue when storing an element.
+ *
+ * <p>{@code BlockingQueue} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table class="plain">
+ * <caption>Summary of BlockingQueue methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Throws exception</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Special value</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Blocks</th>
+ *    <th scope="col" style="font-weight:normal; font-style:italic">Times out</th>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left">Insert</th>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #put(Object) put(e)}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left">Remove</th>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #poll() poll()}</td>
+ *    <td>{@link #take() take()}</td>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left">Examine</th>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #peek() peek()}</td>
+ *    <td style="font-style: italic">not applicable</td>
+ *    <td style="font-style: italic">not applicable</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>A {@code BlockingQueue} does not accept {@code null} elements.
+ * Implementations throw {@code NullPointerException} on attempts
+ * to {@code add}, {@code put} or {@code offer} a {@code null}.  A
+ * {@code null} is used as a sentinel value to indicate failure of
+ * {@code poll} operations.
+ *
+ * <p>A {@code BlockingQueue} may be capacity bounded. At any given
+ * time it may have a {@code remainingCapacity} beyond which no
+ * additional elements can be {@code put} without blocking.
+ * A {@code BlockingQueue} without any intrinsic capacity constraints always
+ * reports a remaining capacity of {@code Integer.MAX_VALUE}.
+ *
+ * <p>{@code BlockingQueue} implementations are designed to be used
+ * primarily for producer-consumer queues, but additionally support
+ * the {@link Collection} interface.  So, for example, it is
+ * possible to remove an arbitrary element from a queue using
+ * {@code remove(x)}. However, such operations are in general
+ * <em>not</em> performed very efficiently, and are intended for only
+ * occasional use, such as when a queued message is cancelled.
+ *
+ * <p>{@code BlockingQueue} implementations are thread-safe.  All
+ * queuing methods achieve their effects atomically using internal
+ * locks or other forms of concurrency control. However, the
+ * <em>bulk</em> Collection operations {@code addAll},
+ * {@code containsAll}, {@code retainAll} and {@code removeAll} are
+ * <em>not</em> necessarily performed atomically unless specified
+ * otherwise in an implementation. So it is possible, for example, for
+ * {@code addAll(c)} to fail (throwing an exception) after adding
+ * only some of the elements in {@code c}.
+ *
+ * <p>A {@code BlockingQueue} does <em>not</em> intrinsically support
+ * any kind of &quot;close&quot; or &quot;shutdown&quot; operation to
+ * indicate that no more items will be added.  The needs and usage of
+ * such features tend to be implementation-dependent. For example, a
+ * common tactic is for producers to insert special
+ * <em>end-of-stream</em> or <em>poison</em> objects, that are
+ * interpreted accordingly when taken by consumers.
+ *
+ * <p>
+ * Usage example, based on a typical producer-consumer scenario.
+ * Note that a {@code BlockingQueue} can safely be used with multiple
+ * producers and multiple consumers.
+ * <pre> {@code
+ * class Producer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Producer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { queue.put(produce()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   Object produce() { ... }
+ * }
+ *
+ * class Consumer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Consumer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { consume(queue.take()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   void consume(Object x) { ... }
+ * }
+ *
+ * class Setup {
+ *   void main() {
+ *     BlockingQueue q = new SomeQueueImplementation();
+ *     Producer p = new Producer(q);
+ *     Consumer c1 = new Consumer(q);
+ *     Consumer c2 = new Consumer(q);
+ *     new Thread(p).start();
+ *     new Thread(c1).start();
+ *     new Thread(c2).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingQueue} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface BlockingQueue<E> extends Queue<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted queue, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @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 add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted queue, this method is
+     * generally preferable to {@link #add}, which can fail to insert an
+     * element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, 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 offer(E e);
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @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 put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into this queue, waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @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 space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @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 offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element becomes available.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * @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 head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking, or {@code Integer.MAX_VALUE} if there is no intrinsic
+     * limit.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     *
+     * @return the remaining capacity
+     */
+    int remainingCapacity();
+
+    /**
+     * 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
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object 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
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Removes all available elements from this queue and adds them
+     * to the given collection.  This operation may be more
+     * efficient than repeatedly polling this queue.  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.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, 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
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c);
+
+    /**
+     * Removes at most the given number of available elements from
+     * this queue and adds them to the given collection.  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.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, 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
+     * @param maxElements the maximum number of elements to transfer
+     * @return the number of elements transferred
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c, int maxElements);
+}
diff --git a/android-35/java/util/concurrent/BrokenBarrierException.java b/android-35/java/util/concurrent/BrokenBarrierException.java
new file mode 100644
index 0000000..11f126e
--- /dev/null
+++ b/android-35/java/util/concurrent/BrokenBarrierException.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a thread tries to wait upon a barrier that is
+ * in a broken state, or which enters the broken state while the thread
+ * is waiting.
+ *
+ * @see CyclicBarrier
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class BrokenBarrierException extends Exception {
+    private static final long serialVersionUID = 7117394618823254244L;
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with no specified detail
+     * message.
+     */
+    public BrokenBarrierException() {}
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with the specified
+     * detail message.
+     *
+     * @param message the detail message
+     */
+    public BrokenBarrierException(String message) {
+        super(message);
+    }
+}
diff --git a/android-35/java/util/concurrent/Callable.java b/android-35/java/util/concurrent/Callable.java
new file mode 100644
index 0000000..04bc607
--- /dev/null
+++ b/android-35/java/util/concurrent/Callable.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A task that returns a result and may throw an exception.
+ * Implementors define a single method with no arguments called
+ * {@code call}.
+ *
+ * <p>The {@code Callable} interface is similar to {@link
+ * java.lang.Runnable}, in that both are designed for classes whose
+ * instances are potentially executed by another thread.  A
+ * {@code Runnable}, however, does not return a result and cannot
+ * throw a checked exception.
+ *
+ * <p>The {@link Executors} class contains utility methods to
+ * convert from other common forms to {@code Callable} classes.
+ *
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> the result type of method {@code call}
+ */
+@FunctionalInterface
+public interface Callable<V> {
+    /**
+     * Computes a result, or throws an exception if unable to do so.
+     *
+     * @return computed result
+     * @throws Exception if unable to compute a result
+     */
+    V call() throws Exception;
+}
diff --git a/android-35/java/util/concurrent/CancellationException.java b/android-35/java/util/concurrent/CancellationException.java
new file mode 100644
index 0000000..bd35173
--- /dev/null
+++ b/android-35/java/util/concurrent/CancellationException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception indicating that the result of a value-producing task,
+ * such as a {@link FutureTask}, cannot be retrieved because the task
+ * was cancelled.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CancellationException extends IllegalStateException {
+    private static final long serialVersionUID = -9202173006928992231L;
+
+    /**
+     * Constructs a {@code CancellationException} with no detail message.
+     */
+    public CancellationException() {}
+
+    /**
+     * Constructs a {@code CancellationException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public CancellationException(String message) {
+        super(message);
+    }
+}
diff --git a/android-35/java/util/concurrent/CompletableFuture.java b/android-35/java/util/concurrent/CompletableFuture.java
new file mode 100644
index 0000000..63d1598
--- /dev/null
+++ b/android-35/java/util/concurrent/CompletableFuture.java
@@ -0,0 +1,2963 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.Objects;
+
+// Android-note: Class javadoc changed to remove references to hidden OpenJDK 9 methods.
+
+/**
+ * A {@link Future} that may be explicitly completed (setting its
+ * value and status), and may be used as a {@link CompletionStage},
+ * supporting dependent functions and actions that trigger upon its
+ * completion.
+ *
+ * <p>When two or more threads attempt to
+ * {@link #complete complete},
+ * {@link #completeExceptionally completeExceptionally}, or
+ * {@link #cancel cancel}
+ * a CompletableFuture, only one of them succeeds.
+ *
+ * <p>In addition to these and related methods for directly
+ * manipulating status and results, CompletableFuture implements
+ * interface {@link CompletionStage} with the following policies: <ul>
+ *
+ * <li>Actions supplied for dependent completions of
+ * <em>non-async</em> methods may be performed by the thread that
+ * completes the current CompletableFuture, or by any other caller of
+ * a completion method.
+ *
+ * <li>All <em>async</em> methods without an explicit Executor
+ * argument are performed using the {@link ForkJoinPool#commonPool()}
+ * (unless it does not support a parallelism level of at least two, in
+ * which case, a new Thread is created to run each task).
+ * To simplify monitoring, debugging,
+ * and tracking, all generated asynchronous tasks are instances of the
+ * marker interface {@link AsynchronousCompletionTask}.  Operations
+ * with time-delays can use adapter methods defined in this class, for
+ * example: {@code supplyAsync(supplier, delayedExecutor(timeout,
+ * timeUnit))}.  To support methods with delays and timeouts, this
+ * class maintains at most one daemon thread for triggering and
+ * cancelling actions, not for running them.
+ *
+ * <li>All CompletionStage methods are implemented independently of
+ * other public methods, so the behavior of one method is not impacted
+ * by overrides of others in subclasses.
+ *
+ * </ul>
+ *
+ * <p>CompletableFuture also implements {@link Future} with the following
+ * policies: <ul>
+ *
+ * <li>Since (unlike {@link FutureTask}) this class has no direct
+ * control over the computation that causes it to be completed,
+ * cancellation is treated as just another form of exceptional
+ * completion.  Method {@link #cancel cancel} has the same effect as
+ * {@code completeExceptionally(new CancellationException())}. Method
+ * {@link #isCompletedExceptionally} can be used to determine if a
+ * CompletableFuture completed in any exceptional fashion.
+ *
+ * <li>In case of exceptional completion with a CompletionException,
+ * methods {@link #get()} and {@link #get(long, TimeUnit)} throw an
+ * {@link ExecutionException} with the same cause as held in the
+ * corresponding CompletionException.  To simplify usage in most
+ * contexts, this class also defines methods {@link #join()} and
+ * {@link #getNow} that instead throw the CompletionException directly
+ * in these cases.
+ * </ul>
+ *
+ * <p>Arguments used to pass a completion result (that is, for
+ * parameters of type {@code T}) for methods accepting them may be
+ * null, but passing a null value for any other parameter will result
+ * in a {@link NullPointerException} being thrown.
+ *
+ * @author Doug Lea
+ * @param <T> The result type returned by this future's {@code join}
+ * and {@code get} methods
+ * @since 1.8
+ */
+public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
+
+    /*
+     * Overview:
+     *
+     * A CompletableFuture may have dependent completion actions,
+     * collected in a linked stack. It atomically completes by CASing
+     * a result field, and then pops off and runs those actions. This
+     * applies across normal vs exceptional outcomes, sync vs async
+     * actions, binary triggers, and various forms of completions.
+     *
+     * Non-nullness of volatile field "result" indicates done.  It may
+     * be set directly if known to be thread-confined, else via CAS.
+     * An AltResult is used to box null as a result, as well as to
+     * hold exceptions.  Using a single field makes completion simple
+     * to detect and trigger.  Result encoding and decoding is
+     * straightforward but tedious and adds to the sprawl of trapping
+     * and associating exceptions with targets.  Minor simplifications
+     * rely on (static) NIL (to box null results) being the only
+     * AltResult with a null exception field, so we don't usually need
+     * explicit comparisons.  Even though some of the generics casts
+     * are unchecked (see SuppressWarnings annotations), they are
+     * placed to be appropriate even if checked.
+     *
+     * Dependent actions are represented by Completion objects linked
+     * as Treiber stacks headed by field "stack". There are Completion
+     * classes for each kind of action, grouped into:
+     * - single-input (UniCompletion),
+     * - two-input (BiCompletion),
+     * - projected (BiCompletions using exactly one of two inputs),
+     * - shared (CoCompletion, used by the second of two sources),
+     * - zero-input source actions,
+     * - Signallers that unblock waiters.
+     * Class Completion extends ForkJoinTask to enable async execution
+     * (adding no space overhead because we exploit its "tag" methods
+     * to maintain claims). It is also declared as Runnable to allow
+     * usage with arbitrary executors.
+     *
+     * Support for each kind of CompletionStage relies on a separate
+     * class, along with two CompletableFuture methods:
+     *
+     * * A Completion class with name X corresponding to function,
+     *   prefaced with "Uni", "Bi", or "Or". Each class contains
+     *   fields for source(s), actions, and dependent. They are
+     *   boringly similar, differing from others only with respect to
+     *   underlying functional forms. We do this so that users don't
+     *   encounter layers of adapters in common usages.
+     *
+     * * Boolean CompletableFuture method x(...) (for example
+     *   biApply) takes all of the arguments needed to check that an
+     *   action is triggerable, and then either runs the action or
+     *   arranges its async execution by executing its Completion
+     *   argument, if present. The method returns true if known to be
+     *   complete.
+     *
+     * * Completion method tryFire(int mode) invokes the associated x
+     *   method with its held arguments, and on success cleans up.
+     *   The mode argument allows tryFire to be called twice (SYNC,
+     *   then ASYNC); the first to screen and trap exceptions while
+     *   arranging to execute, and the second when called from a task.
+     *   (A few classes are not used async so take slightly different
+     *   forms.)  The claim() callback suppresses function invocation
+     *   if already claimed by another thread.
+     *
+     * * Some classes (for example UniApply) have separate handling
+     *   code for when known to be thread-confined ("now" methods) and
+     *   for when shared (in tryFire), for efficiency.
+     *
+     * * CompletableFuture method xStage(...) is called from a public
+     *   stage method of CompletableFuture f. It screens user
+     *   arguments and invokes and/or creates the stage object.  If
+     *   not async and already triggerable, the action is run
+     *   immediately.  Otherwise a Completion c is created, and
+     *   submitted to the executor if triggerable, or pushed onto f's
+     *   stack if not.  Completion actions are started via c.tryFire.
+     *   We recheck after pushing to a source future's stack to cover
+     *   possible races if the source completes while pushing.
+     *   Classes with two inputs (for example BiApply) deal with races
+     *   across both while pushing actions.  The second completion is
+     *   a CoCompletion pointing to the first, shared so that at most
+     *   one performs the action.  The multiple-arity methods allOf
+     *   does this pairwise to form trees of completions.  Method
+     *   anyOf is handled differently from allOf because completion of
+     *   any source should trigger a cleanStack of other sources.
+     *   Each AnyOf completion can reach others via a shared array.
+     *
+     * Note that the generic type parameters of methods vary according
+     * to whether "this" is a source, dependent, or completion.
+     *
+     * Method postComplete is called upon completion unless the target
+     * is guaranteed not to be observable (i.e., not yet returned or
+     * linked). Multiple threads can call postComplete, which
+     * atomically pops each dependent action, and tries to trigger it
+     * via method tryFire, in NESTED mode.  Triggering can propagate
+     * recursively, so NESTED mode returns its completed dependent (if
+     * one exists) for further processing by its caller (see method
+     * postFire).
+     *
+     * Blocking methods get() and join() rely on Signaller Completions
+     * that wake up waiting threads.  The mechanics are similar to
+     * Treiber stack wait-nodes used in FutureTask, Phaser, and
+     * SynchronousQueue. See their internal documentation for
+     * algorithmic details.
+     *
+     * Without precautions, CompletableFutures would be prone to
+     * garbage accumulation as chains of Completions build up, each
+     * pointing back to its sources. So we null out fields as soon as
+     * possible.  The screening checks needed anyway harmlessly ignore
+     * null arguments that may have been obtained during races with
+     * threads nulling out fields.  We also try to unlink non-isLive
+     * (fired or cancelled) Completions from stacks that might
+     * otherwise never be popped: Method cleanStack always unlinks non
+     * isLive completions from the head of stack; others may
+     * occasionally remain if racing with other cancellations or
+     * removals.
+     *
+     * Completion fields need not be declared as final or volatile
+     * because they are only visible to other threads upon safe
+     * publication.
+     */
+
+    volatile Object result;       // Either the result or boxed AltResult
+    volatile Completion stack;    // Top of Treiber stack of dependent actions
+
+    final boolean internalComplete(Object r) { // CAS from null to r
+        return RESULT.compareAndSet(this, null, r);
+    }
+
+    /** Returns true if successfully pushed c onto stack. */
+    final boolean tryPushStack(Completion c) {
+        Completion h = stack;
+        NEXT.set(c, h);         // CAS piggyback
+        return STACK.compareAndSet(this, h, c);
+    }
+
+    /** Unconditionally pushes c onto stack, retrying if necessary. */
+    final void pushStack(Completion c) {
+        do {} while (!tryPushStack(c));
+    }
+
+    /* ------------- Encoding and decoding outcomes -------------- */
+
+    static final class AltResult { // See above
+        final Throwable ex;        // null only for NIL
+        AltResult(Throwable x) { this.ex = x; }
+    }
+
+    /** The encoding of the null value. */
+    static final AltResult NIL = new AltResult(null);
+
+    /** Completes with the null value, unless already completed. */
+    final boolean completeNull() {
+        return RESULT.compareAndSet(this, null, NIL);
+    }
+
+    /** Returns the encoding of the given non-exceptional value. */
+    final Object encodeValue(T t) {
+        return (t == null) ? NIL : t;
+    }
+
+    /** Completes with a non-exceptional result, unless already completed. */
+    final boolean completeValue(T t) {
+        return RESULT.compareAndSet(this, null, (t == null) ? NIL : t);
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.
+     */
+    static AltResult encodeThrowable(Throwable x) {
+        return new AltResult((x instanceof CompletionException) ? x :
+                             new CompletionException(x));
+    }
+
+    /** Completes with an exceptional result, unless already completed. */
+    final boolean completeThrowable(Throwable x) {
+        return RESULT.compareAndSet(this, null, encodeThrowable(x));
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.  May
+     * return the given Object r (which must have been the result of a
+     * source future) if it is equivalent, i.e. if this is a simple
+     * relay of an existing CompletionException.
+     */
+    static Object encodeThrowable(Throwable x, Object r) {
+        if (!(x instanceof CompletionException))
+            x = new CompletionException(x);
+        else if (r instanceof AltResult && x == ((AltResult)r).ex)
+            return r;
+        return new AltResult(x);
+    }
+
+    /**
+     * Completes with the given (non-null) exceptional result as a
+     * wrapped CompletionException unless it is one already, unless
+     * already completed.  May complete with the given Object r
+     * (which must have been the result of a source future) if it is
+     * equivalent, i.e. if this is a simple propagation of an
+     * existing CompletionException.
+     */
+    final boolean completeThrowable(Throwable x, Object r) {
+        return RESULT.compareAndSet(this, null, encodeThrowable(x, r));
+    }
+
+    /**
+     * Returns the encoding of the given arguments: if the exception
+     * is non-null, encodes as AltResult.  Otherwise uses the given
+     * value, boxed as NIL if null.
+     */
+    Object encodeOutcome(T t, Throwable x) {
+        return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+    }
+
+    /**
+     * Returns the encoding of a copied outcome; if exceptional,
+     * rewraps as a CompletionException, else returns argument.
+     */
+    static Object encodeRelay(Object r) {
+        Throwable x;
+        if (r instanceof AltResult
+            && (x = ((AltResult)r).ex) != null
+            && !(x instanceof CompletionException))
+            r = new AltResult(new CompletionException(x));
+        return r;
+    }
+
+    /**
+     * Completes with r or a copy of r, unless already completed.
+     * If exceptional, r is first coerced to a CompletionException.
+     */
+    final boolean completeRelay(Object r) {
+        return RESULT.compareAndSet(this, null, encodeRelay(r));
+    }
+
+    /**
+     * Reports result using Future.get conventions.
+     */
+    private static Object reportGet(Object r)
+        throws InterruptedException, ExecutionException {
+        if (r == null) // by convention below, null means interrupted
+            throw new InterruptedException();
+        if (r instanceof AltResult) {
+            Throwable x, cause;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if ((x instanceof CompletionException) &&
+                (cause = x.getCause()) != null)
+                x = cause;
+            throw new ExecutionException(x);
+        }
+        return r;
+    }
+
+    /**
+     * Decodes outcome to return result or throw unchecked exception.
+     */
+    private static Object reportJoin(Object r) {
+        if (r instanceof AltResult) {
+            Throwable x;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if (x instanceof CompletionException)
+                throw (CompletionException)x;
+            throw new CompletionException(x);
+        }
+        return r;
+    }
+
+    /* ------------- Async task preliminaries -------------- */
+
+    /**
+     * A marker interface identifying asynchronous tasks produced by
+     * {@code async} methods. This may be useful for monitoring,
+     * debugging, and tracking asynchronous activities.
+     *
+     * @since 1.8
+     */
+    public static interface AsynchronousCompletionTask {
+    }
+
+    private static final boolean USE_COMMON_POOL =
+        (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    static final class ThreadPerTaskExecutor implements Executor {
+        public void execute(Runnable r) {
+            Objects.requireNonNull(r);
+            new Thread(r).start();
+        }
+    }
+
+    /**
+     * Null-checks user executor argument, and translates uses of
+     * commonPool to ASYNC_POOL in case parallelism disabled.
+     */
+    static Executor screenExecutor(Executor e) {
+        if (!USE_COMMON_POOL && e == ForkJoinPool.commonPool())
+            return ASYNC_POOL;
+        if (e == null) throw new NullPointerException();
+        return e;
+    }
+
+    // Modes for Completion.tryFire. Signedness matters.
+    static final int SYNC   =  0;
+    static final int ASYNC  =  1;
+    static final int NESTED = -1;
+
+    /* ------------- Base Completion classes and operations -------------- */
+
+    @SuppressWarnings("serial")
+    abstract static class Completion extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        volatile Completion next;      // Treiber stack link
+
+        /**
+         * Performs completion action if triggered, returning a
+         * dependent that may need propagation, if one exists.
+         *
+         * @param mode SYNC, ASYNC, or NESTED
+         */
+        abstract CompletableFuture<?> tryFire(int mode);
+
+        /** Returns true if possibly still triggerable. Used by cleanStack. */
+        abstract boolean isLive();
+
+        public final void run()                { tryFire(ASYNC); }
+        public final boolean exec()            { tryFire(ASYNC); return false; }
+        public final Void getRawResult()       { return null; }
+        public final void setRawResult(Void v) {}
+    }
+
+    /**
+     * Pops and tries to trigger all reachable dependents.  Call only
+     * when known to be done.
+     */
+    final void postComplete() {
+        /*
+         * On each step, variable f holds current dependents to pop
+         * and run.  It is extended along only one path at a time,
+         * pushing others to avoid unbounded recursion.
+         */
+        CompletableFuture<?> f = this; Completion h;
+        while ((h = f.stack) != null ||
+               (f != this && (h = (f = this).stack) != null)) {
+            CompletableFuture<?> d; Completion t;
+            if (STACK.compareAndSet(f, h, t = h.next)) {
+                if (t != null) {
+                    if (f != this) {
+                        pushStack(h);
+                        continue;
+                    }
+                    NEXT.compareAndSet(h, t, null); // try to detach
+                }
+                f = (d = h.tryFire(NESTED)) == null ? this : d;
+            }
+        }
+    }
+
+    /** Traverses stack and unlinks one or more dead Completions, if found. */
+    final void cleanStack() {
+        Completion p = stack;
+        // ensure head of stack live
+        for (boolean unlinked = false;;) {
+            if (p == null)
+                return;
+            else if (p.isLive()) {
+                if (unlinked)
+                    return;
+                else
+                    break;
+            }
+            else if (STACK.weakCompareAndSet(this, p, (p = p.next)))
+                unlinked = true;
+            else
+                p = stack;
+        }
+        // try to unlink first non-live
+        for (Completion q = p.next; q != null;) {
+            Completion s = q.next;
+            if (q.isLive()) {
+                p = q;
+                q = s;
+            } else if (NEXT.weakCompareAndSet(p, q, s))
+                break;
+            else
+                q = p.next;
+        }
+    }
+
+    /* ------------- One-input Completions -------------- */
+
+    /** A Completion with a source, dependent, and executor. */
+    @SuppressWarnings("serial")
+    abstract static class UniCompletion<T,V> extends Completion {
+        Executor executor;                 // executor to use (null if none)
+        CompletableFuture<V> dep;          // the dependent to complete
+        CompletableFuture<T> src;          // source for action
+
+        UniCompletion(Executor executor, CompletableFuture<V> dep,
+                      CompletableFuture<T> src) {
+            this.executor = executor; this.dep = dep; this.src = src;
+        }
+
+        /**
+         * Returns true if action can be run. Call only when known to
+         * be triggerable. Uses FJ tag bit to ensure that only one
+         * thread claims ownership.  If async, starts as task -- a
+         * later call to tryFire will run action.
+         */
+        final boolean claim() {
+            Executor e = executor;
+            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+                if (e == null)
+                    return true;
+                executor = null; // disable
+                e.execute(this);
+            }
+            return false;
+        }
+
+        final boolean isLive() { return dep != null; }
+    }
+
+    /**
+     * Pushes the given completion unless it completes while trying.
+     * Caller should first check that result is null.
+     */
+    final void unipush(Completion c) {
+        if (c != null) {
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
+                    break;
+                }
+            }
+            if (result != null)
+                c.tryFire(SYNC);
+        }
+    }
+
+    /**
+     * Post-processing by dependent after successful UniCompletion tryFire.
+     * Tries to clean stack of source a, and then either runs postComplete
+     * or returns this to caller, depending on mode.
+     */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+        if (a != null && a.stack != null) {
+            Object r;
+            if ((r = a.result) == null)
+                a.cleanStack();
+            if (mode >= 0 && (r != null || a.result != null))
+                a.postComplete();
+        }
+        if (result != null && stack != null) {
+            if (mode < 0)
+                return this;
+            else
+                postComplete();
+        }
+        return null;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniApply<T,V> extends UniCompletion<T,V> {
+        Function<? super T,? extends V> fn;
+        UniApply(Executor executor, CompletableFuture<V> dep,
+                 CompletableFuture<T> src,
+                 Function<? super T,? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        d.completeValue(f.apply(t));
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private <V> CompletableFuture<V> uniApplyStage(
+        Executor e, Function<? super T,? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniApplyNow(r, e, f);
+        CompletableFuture<V> d = newIncompleteFuture();
+        unipush(new UniApply<T,V>(e, d, this, f));
+        return d;
+    }
+
+    private <V> CompletableFuture<V> uniApplyNow(
+        Object r, Executor e, Function<? super T,? extends V> f) {
+        Throwable x;
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniApply<T,V>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                d.result = d.encodeValue(f.apply(t));
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniAccept<T> extends UniCompletion<T,Void> {
+        Consumer<? super T> fn;
+        UniAccept(Executor executor, CompletableFuture<Void> dep,
+                  CompletableFuture<T> src, Consumer<? super T> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else {
+                        @SuppressWarnings("unchecked") T t = (T) r;
+                        f.accept(t);
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private CompletableFuture<Void> uniAcceptStage(Executor e,
+                                                   Consumer<? super T> f) {
+        if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniAcceptNow(r, e, f);
+        CompletableFuture<Void> d = newIncompleteFuture();
+        unipush(new UniAccept<T>(e, d, this, f));
+        return d;
+    }
+
+    private CompletableFuture<Void> uniAcceptNow(
+        Object r, Executor e, Consumer<? super T> f) {
+        Throwable x;
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (r instanceof AltResult) {
+            if ((x = ((AltResult)r).ex) != null) {
+                d.result = encodeThrowable(x, r);
+                return d;
+            }
+            r = null;
+        }
+        try {
+            if (e != null) {
+                e.execute(new UniAccept<T>(null, d, this, f));
+            } else {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                f.accept(t);
+                d.result = NIL;
+            }
+        } catch (Throwable ex) {
+            d.result = encodeThrowable(ex);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRun<T> extends UniCompletion<T,Void> {
+        Runnable fn;
+        UniRun(Executor executor, CompletableFuture<Void> dep,
+               CompletableFuture<T> src, Runnable fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            Object r; Throwable x; Runnable f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            if (d.result == null) {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    d.completeThrowable(x, r);
+                else
+                    try {
+                        if (mode <= 0 && !claim())
+                            return null;
+                        else {
+                            f.run();
+                            d.completeNull();
+                        }
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+            }
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        Object r;
+        if ((r = result) != null)
+            return uniRunNow(r, e, f);
+        CompletableFuture<Void> d = newIncompleteFuture();
+        unipush(new UniRun<T>(e, d, this, f));
+        return d;
+    }
+
+    private CompletableFuture<Void> uniRunNow(Object r, Executor e, Runnable f) {
+        Throwable x;
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+            d.result = encodeThrowable(x, r);
+        else
+            try {
+                if (e != null) {
+                    e.execute(new UniRun<T>(null, d, this, f));
+                } else {
+                    f.run();
+                    d.result = NIL;
+                }
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+        BiConsumer<? super T, ? super Throwable> fn;
+        UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+                        CompletableFuture<T> src,
+                        BiConsumer<? super T, ? super Throwable> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            Object r; BiConsumer<? super T, ? super Throwable> f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.uniWhenComplete(r, f, mode > 0 ? null : this))
+                return null;
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniWhenComplete(Object r,
+                                  BiConsumer<? super T,? super Throwable> f,
+                                  UniWhenComplete<T> c) {
+        T t; Throwable x = null;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    t = null;
+                } else {
+                    @SuppressWarnings("unchecked") T tr = (T) r;
+                    t = tr;
+                }
+                f.accept(t, x);
+                if (x == null) {
+                    internalComplete(r);
+                    return true;
+                }
+            } catch (Throwable ex) {
+                if (x == null)
+                    x = ex;
+                else if (x != ex)
+                    x.addSuppressed(ex);
+            }
+            completeThrowable(x, r);
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniWhenCompleteStage(
+        Executor e, BiConsumer<? super T, ? super Throwable> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniWhenComplete<T>(e, d, this, f));
+        else if (e == null)
+            d.uniWhenComplete(r, f, null);
+        else {
+            try {
+                e.execute(new UniWhenComplete<T>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniHandle<T,V> extends UniCompletion<T,V> {
+        BiFunction<? super T, Throwable, ? extends V> fn;
+        UniHandle(Executor executor, CompletableFuture<V> dep,
+                  CompletableFuture<T> src,
+                  BiFunction<? super T, Throwable, ? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            Object r; BiFunction<? super T, Throwable, ? extends V> f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.uniHandle(r, f, mode > 0 ? null : this))
+                return null;
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniHandle(Object r,
+                                BiFunction<? super S, Throwable, ? extends T> f,
+                                UniHandle<S,T> c) {
+        S s; Throwable x;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    s = null;
+                } else {
+                    x = null;
+                    @SuppressWarnings("unchecked") S ss = (S) r;
+                    s = ss;
+                }
+                completeValue(f.apply(s, x));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniHandleStage(
+        Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniHandle<T,V>(e, d, this, f));
+        else if (e == null)
+            d.uniHandle(r, f, null);
+        else {
+            try {
+                e.execute(new UniHandle<T,V>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniExceptionally<T> extends UniCompletion<T,T> {
+        Function<? super Throwable, ? extends T> fn;
+        UniExceptionally(Executor executor,
+                         CompletableFuture<T> dep, CompletableFuture<T> src,
+                         Function<? super Throwable, ? extends T> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            Object r; Function<? super Throwable, ? extends T> f;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.uniExceptionally(r, f, mode > 0 ? null : this))
+                return null;
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniExceptionally(Object r,
+                                   Function<? super Throwable, ? extends T> f,
+                                   UniExceptionally<T> c) {
+        Throwable x;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    completeValue(f.apply(x));
+                else
+                    internalComplete(r);
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniExceptionallyStage(
+        Executor e, Function<Throwable, ? extends T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        Object r;
+        if ((r = result) == null)
+            unipush(new UniExceptionally<T>(e, d, this, f));
+        else if (e == null)
+            d.uniExceptionally(r, f, null);
+        else {
+            try {
+                e.execute(new UniExceptionally<T>(null, d, this, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniComposeExceptionally<T> extends UniCompletion<T,T> {
+        Function<Throwable, ? extends CompletionStage<T>> fn;
+        UniComposeExceptionally(Executor executor, CompletableFuture<T> dep,
+                                CompletableFuture<T> src,
+                                Function<Throwable, ? extends CompletionStage<T>> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            Function<Throwable, ? extends CompletionStage<T>> f;
+            Object r; Throwable x;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            if (d.result == null) {
+                if ((r instanceof AltResult) &&
+                    (x = ((AltResult)r).ex) != null) {
+                    try {
+                        if (mode <= 0 && !claim())
+                            return null;
+                        CompletableFuture<T> g = f.apply(x).toCompletableFuture();
+                        if ((r = g.result) != null)
+                            d.completeRelay(r);
+                        else {
+                            g.unipush(new UniRelay<T,T>(d, g));
+                            if (d.result == null)
+                                return null;
+                        }
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                else
+                    d.internalComplete(r);
+            }
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private CompletableFuture<T> uniComposeExceptionallyStage(
+        Executor e, Function<Throwable, ? extends CompletionStage<T>> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        Object r, s; Throwable x;
+        if ((r = result) == null)
+            unipush(new UniComposeExceptionally<T>(e, d, this, f));
+        else if (!(r instanceof AltResult) || (x = ((AltResult)r).ex) == null)
+            d.internalComplete(r);
+        else
+            try {
+                if (e != null)
+                    e.execute(new UniComposeExceptionally<T>(null, d, this, f));
+                else {
+                    CompletableFuture<T> g = f.apply(x).toCompletableFuture();
+                    if ((s = g.result) != null)
+                        d.result = encodeRelay(s);
+                    else
+                        g.unipush(new UniRelay<T,T>(d, g));
+                }
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
+        UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
+            super(null, dep, src);
+        }
+        final CompletableFuture<U> tryFire(int mode) {
+            CompletableFuture<U> d; CompletableFuture<T> a; Object r;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null)
+                return null;
+            if (d.result == null)
+                d.completeRelay(r);
+            src = null; dep = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private static <U, T extends U> CompletableFuture<U> uniCopyStage(
+        CompletableFuture<T> src) {
+        Object r;
+        CompletableFuture<U> d = src.newIncompleteFuture();
+        if ((r = src.result) != null)
+            d.result = encodeRelay(r);
+        else
+            src.unipush(new UniRelay<U,T>(d, src));
+        return d;
+    }
+
+    private MinimalStage<T> uniAsMinimalStage() {
+        Object r;
+        if ((r = result) != null)
+            return new MinimalStage<T>(encodeRelay(r));
+        MinimalStage<T> d = new MinimalStage<T>();
+        unipush(new UniRelay<T,T>(d, this));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniCompose<T,V> extends UniCompletion<T,V> {
+        Function<? super T, ? extends CompletionStage<V>> fn;
+        UniCompose(Executor executor, CompletableFuture<V> dep,
+                   CompletableFuture<T> src,
+                   Function<? super T, ? extends CompletionStage<V>> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            Function<? super T, ? extends CompletionStage<V>> f;
+            Object r; Throwable x;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            tryComplete: if (d.result == null) {
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        d.completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                    if ((r = g.result) != null)
+                        d.completeRelay(r);
+                    else {
+                        g.unipush(new UniRelay<V,V>(d, g));
+                        if (d.result == null)
+                            return null;
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; dep = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    private <V> CompletableFuture<V> uniComposeStage(
+        Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        Object r, s; Throwable x;
+        if ((r = result) == null)
+            unipush(new UniCompose<T,V>(e, d, this, f));
+        else {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    d.result = encodeThrowable(x, r);
+                    return d;
+                }
+                r = null;
+            }
+            try {
+                if (e != null)
+                    e.execute(new UniCompose<T,V>(null, d, this, f));
+                else {
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                    if ((s = g.result) != null)
+                        d.result = encodeRelay(s);
+                    else
+                        g.unipush(new UniRelay<V,V>(d, g));
+                }
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Two-input Completions -------------- */
+
+    /** A Completion for an action with two sources */
+    @SuppressWarnings("serial")
+    abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+        CompletableFuture<U> snd; // second source for action
+        BiCompletion(Executor executor, CompletableFuture<V> dep,
+                     CompletableFuture<T> src, CompletableFuture<U> snd) {
+            super(executor, dep, src); this.snd = snd;
+        }
+    }
+
+    /** A Completion delegating to a BiCompletion */
+    @SuppressWarnings("serial")
+    static final class CoCompletion extends Completion {
+        BiCompletion<?,?,?> base;
+        CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+        final CompletableFuture<?> tryFire(int mode) {
+            BiCompletion<?,?,?> c; CompletableFuture<?> d;
+            if ((c = base) == null || (d = c.tryFire(mode)) == null)
+                return null;
+            base = null; // detach
+            return d;
+        }
+        final boolean isLive() {
+            BiCompletion<?,?,?> c;
+            return (c = base) != null
+                // && c.isLive()
+                && c.dep != null;
+        }
+    }
+
+    /**
+     * Pushes completion to this and b unless both done.
+     * Caller should first check that either result or b.result is null.
+     */
+    final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            while (result == null) {
+                if (tryPushStack(c)) {
+                    if (b.result == null)
+                        b.unipush(new CoCompletion(c));
+                    else if (result != null)
+                        c.tryFire(SYNC);
+                    return;
+                }
+            }
+            b.unipush(c);
+        }
+    }
+
+    /** Post-processing after successful BiCompletion tryFire. */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a,
+                                        CompletableFuture<?> b, int mode) {
+        if (b != null && b.stack != null) { // clean second source
+            Object r;
+            if ((r = b.result) == null)
+                b.cleanStack();
+            if (mode >= 0 && (r != null || b.result != null))
+                b.postComplete();
+        }
+        return postFire(a, mode);
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+        BiFunction<? super T,? super U,? extends V> fn;
+        BiApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
+                BiFunction<? super T,? super U,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            Object r, s; BiFunction<? super T,? super U,? extends V> f;
+            if (   (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.biApply(r, s, f, mode > 0 ? null : this))
+                return null;
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biApply(Object r, Object s,
+                                BiFunction<? super R,? super S,? extends T> f,
+                                BiApply<R,S,T> c) {
+        Throwable x;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                completeValue(f.apply(rr, ss));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U,V> CompletableFuture<V> biApplyStage(
+        Executor e, CompletionStage<U> o,
+        BiFunction<? super T,? super U,? extends V> f) {
+        CompletableFuture<U> b; Object r, s;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiApply<T,U,V>(e, d, this, b, f));
+        else if (e == null)
+            d.biApply(r, s, f, null);
+        else
+            try {
+                e.execute(new BiApply<T,U,V>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+        BiConsumer<? super T,? super U> fn;
+        BiAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 BiConsumer<? super T,? super U> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            Object r, s; BiConsumer<? super T,? super U> f;
+            if (   (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.biAccept(r, s, f, mode > 0 ? null : this))
+                return null;
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biAccept(Object r, Object s,
+                                 BiConsumer<? super R,? super S> f,
+                                 BiAccept<R,S> c) {
+        Throwable x;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                f.accept(rr, ss);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U> CompletableFuture<Void> biAcceptStage(
+        Executor e, CompletionStage<U> o,
+        BiConsumer<? super T,? super U> f) {
+        CompletableFuture<U> b; Object r, s;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiAccept<T,U>(e, d, this, b, f));
+        else if (e == null)
+            d.biAccept(r, s, f, null);
+        else
+            try {
+                e.execute(new BiAccept<T,U>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        BiRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            Object r, s; Runnable f;
+            if (   (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || (d = dep) == null || (f = fn) == null
+                || !d.biRun(r, s, f, mode > 0 ? null : this))
+                return null;
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean biRun(Object r, Object s, Runnable f, BiRun<?,?> c) {
+        Throwable x; Object z;
+        if (result == null) {
+            if ((r instanceof AltResult
+                 && (x = ((AltResult)(z = r)).ex) != null) ||
+                (s instanceof AltResult
+                 && (x = ((AltResult)(z = s)).ex) != null))
+                completeThrowable(x, z);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b; Object r, s;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if ((r = result) == null || (s = b.result) == null)
+            bipush(b, new BiRun<>(e, d, this, b, f));
+        else if (e == null)
+            d.biRun(r, s, f, null);
+        else
+            try {
+                e.execute(new BiRun<>(null, d, this, b, f));
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+            }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+        BiRelay(CompletableFuture<Void> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            Object r, s, z; Throwable x;
+            if (   (a = src) == null || (r = a.result) == null
+                || (b = snd) == null || (s = b.result) == null
+                || (d = dep) == null)
+                return null;
+            if (d.result == null) {
+                if ((r instanceof AltResult
+                     && (x = ((AltResult)(z = r)).ex) != null) ||
+                    (s instanceof AltResult
+                     && (x = ((AltResult)(z = s)).ex) != null))
+                    d.completeThrowable(x, z);
+                else
+                    d.completeNull();
+            }
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+                                           int lo, int hi) {
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (lo > hi) // empty
+            d.result = NIL;
+        else {
+            CompletableFuture<?> a, b; Object r, s, z; Throwable x;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      andTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      andTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if ((r = a.result) == null || (s = b.result) == null)
+                a.bipush(b, new BiRelay<>(d, a, b));
+            else if ((r instanceof AltResult
+                      && (x = ((AltResult)(z = r)).ex) != null) ||
+                     (s instanceof AltResult
+                      && (x = ((AltResult)(z = s)).ex) != null))
+                d.result = encodeThrowable(x, z);
+            else
+                d.result = NIL;
+        }
+        return d;
+    }
+
+    /* ------------- Projected (Ored) BiCompletions -------------- */
+
+    /**
+     * Pushes completion to this and b unless either done.
+     * Caller should first check that result and b.result are both null.
+     */
+    final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            while (!tryPushStack(c)) {
+                if (result != null) {
+                    NEXT.set(c, null);
+                    break;
+                }
+            }
+            if (result != null)
+                c.tryFire(SYNC);
+            else
+                b.unipush(new CoCompletion(c));
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+        Function<? super T,? extends V> fn;
+        OrApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
+                Function<? super T,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<? extends T> a, b;
+            Object r; Throwable x; Function<? super T,? extends V> f;
+            if ((a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null)
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    d.completeValue(f.apply(t));
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    private <U extends T,V> CompletableFuture<V> orApplyStage(
+        Executor e, CompletionStage<U> o, Function<? super T, ? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniApplyNow(r, e, f);
+
+        CompletableFuture<V> d = newIncompleteFuture();
+        orpush(b, new OrApply<T,U,V>(e, d, this, b, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+        Consumer<? super T> fn;
+        OrAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 Consumer<? super T> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<? extends T> a, b;
+            Object r; Throwable x; Consumer<? super T> f;
+            if ((a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null)
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            tryComplete: if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    if (r instanceof AltResult) {
+                        if ((x = ((AltResult)r).ex) != null) {
+                            d.completeThrowable(x, r);
+                            break tryComplete;
+                        }
+                        r = null;
+                    }
+                    @SuppressWarnings("unchecked") T t = (T) r;
+                    f.accept(t);
+                    d.completeNull();
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    private <U extends T> CompletableFuture<Void> orAcceptStage(
+        Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+
+        Object r; CompletableFuture<? extends T> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniAcceptNow(r, e, f);
+
+        CompletableFuture<Void> d = newIncompleteFuture();
+        orpush(b, new OrAccept<T,U>(e, d, this, b, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        OrRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src, CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<?> a, b;
+            Object r; Throwable x; Runnable f;
+            if ((a = src) == null || (b = snd) == null
+                || ((r = a.result) == null && (r = b.result) == null)
+                || (d = dep) == null || (f = fn) == null)
+                return null;
+            if (d.result == null) {
+                try {
+                    if (mode <= 0 && !claim())
+                        return null;
+                    else if (r instanceof AltResult
+                        && (x = ((AltResult)r).ex) != null)
+                        d.completeThrowable(x, r);
+                    else {
+                        f.run();
+                        d.completeNull();
+                    }
+                } catch (Throwable ex) {
+                    d.completeThrowable(ex);
+                }
+            }
+            src = null; snd = null; dep = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+
+        Object r; CompletableFuture<?> z;
+        if ((r = (z = this).result) != null ||
+            (r = (z = b).result) != null)
+            return z.uniRunNow(r, e, f);
+
+        CompletableFuture<Void> d = newIncompleteFuture();
+        orpush(b, new OrRun<>(e, d, this, b, f));
+        return d;
+    }
+
+    /** Completion for an anyOf input future. */
+    @SuppressWarnings("serial")
+    static class AnyOf extends Completion {
+        CompletableFuture<Object> dep; CompletableFuture<?> src;
+        CompletableFuture<?>[] srcs;
+        AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
+              CompletableFuture<?>[] srcs) {
+            this.dep = dep; this.src = src; this.srcs = srcs;
+        }
+        final CompletableFuture<Object> tryFire(int mode) {
+            // assert mode != ASYNC;
+            CompletableFuture<Object> d; CompletableFuture<?> a;
+            CompletableFuture<?>[] as;
+            Object r;
+            if ((a = src) == null || (r = a.result) == null
+                || (d = dep) == null || (as = srcs) == null)
+                return null;
+            src = null; dep = null; srcs = null;
+            if (d.completeRelay(r)) {
+                for (CompletableFuture<?> b : as)
+                    if (b != a)
+                        b.cleanStack();
+                if (mode < 0)
+                    return d;
+                else
+                    d.postComplete();
+            }
+            return null;
+        }
+        final boolean isLive() {
+            CompletableFuture<Object> d;
+            return (d = dep) != null && d.result == null;
+        }
+    }
+
+    /* ------------- Zero-input Async forms -------------- */
+
+    @SuppressWarnings("serial")
+    static final class AsyncSupply<T> extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<T> dep; Supplier<? extends T> fn;
+        AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return false; }
+
+        public void run() {
+            CompletableFuture<T> d; Supplier<? extends T> f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        d.completeValue(f.get());
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+                                                     Supplier<U> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<U> d = new CompletableFuture<U>();
+        e.execute(new AsyncSupply<U>(d, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class AsyncRun extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<Void> dep; Runnable fn;
+        AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return false; }
+
+        public void run() {
+            CompletableFuture<Void> d; Runnable f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        f.run();
+                        d.completeNull();
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        e.execute(new AsyncRun(d, f));
+        return d;
+    }
+
+    /* ------------- Signallers -------------- */
+
+    /**
+     * Completion for recording and releasing a waiting thread.  This
+     * class implements ManagedBlocker to avoid starvation when
+     * blocking actions pile up in ForkJoinPools.
+     */
+    @SuppressWarnings("serial")
+    static final class Signaller extends Completion
+        implements ForkJoinPool.ManagedBlocker {
+        long nanos;                    // remaining wait time if timed
+        final long deadline;           // non-zero if timed
+        final boolean interruptible;
+        boolean interrupted;
+        volatile Thread thread;
+
+        Signaller(boolean interruptible, long nanos, long deadline) {
+            this.thread = Thread.currentThread();
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.deadline = deadline;
+        }
+        final CompletableFuture<?> tryFire(int ignore) {
+            Thread w; // no need to atomically claim
+            if ((w = thread) != null) {
+                thread = null;
+                LockSupport.unpark(w);
+            }
+            return null;
+        }
+        public boolean isReleasable() {
+            if (Thread.interrupted())
+                interrupted = true;
+            return ((interrupted && interruptible) ||
+                    (deadline != 0L &&
+                     (nanos <= 0L ||
+                      (nanos = deadline - System.nanoTime()) <= 0L)) ||
+                    thread == null);
+        }
+        public boolean block() {
+            while (!isReleasable()) {
+                if (deadline == 0L)
+                    LockSupport.park(this);
+                else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            return true;
+        }
+        final boolean isLive() { return thread != null; }
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interruptible and
+     * interrupted.
+     */
+    private Object waitingGet(boolean interruptible) {
+        if (interruptible && Thread.interrupted())
+            return null;
+        Signaller q = null;
+        boolean queued = false;
+        Object r;
+        while ((r = result) == null) {
+            if (q == null) {
+                q = new Signaller(interruptible, 0L, 0L);
+                if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                    ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+            }
+            else if (!queued)
+                queued = tryPushStack(q);
+            else if (interruptible && q.interrupted) {
+                q.thread = null;
+                cleanStack();
+                return null;
+            }
+            else {
+                try {
+                    ForkJoinPool.managedBlock(q);
+                } catch (InterruptedException ie) { // currently cannot happen
+                    q.interrupted = true;
+                }
+            }
+        }
+        if (q != null) {
+            q.thread = null;
+            if (q.interrupted)
+                Thread.currentThread().interrupt();
+        }
+        postComplete();
+        return r;
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interrupted, or
+     * throws TimeoutException on timeout.
+     */
+    private Object timedGet(long nanos) throws TimeoutException {
+        long d = System.nanoTime() + nanos;
+        long deadline = (d == 0L) ? 1L : d; // avoid 0
+        boolean interrupted = false, queued = false;
+        Signaller q = null;
+        Object r = null;
+        for (;;) { // order of checking interrupt, result, timeout matters
+            if (interrupted || (interrupted = Thread.interrupted()))
+                break;
+            else if ((r = result) != null)
+                break;
+            else if (nanos <= 0L)
+                break;
+            else if (q == null) {
+                q = new Signaller(true, nanos, deadline);
+                if (Thread.currentThread() instanceof ForkJoinWorkerThread)
+                    ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
+            }
+            else if (!queued)
+                queued = tryPushStack(q);
+            else {
+                try {
+                    ForkJoinPool.managedBlock(q);
+                    interrupted = q.interrupted;
+                    nanos = q.nanos;
+                } catch (InterruptedException ie) {
+                    interrupted = true;
+                }
+            }
+        }
+        if (q != null) {
+            q.thread = null;
+            if (r == null)
+                cleanStack();
+        }
+        if (r != null) {
+            if (interrupted)
+                Thread.currentThread().interrupt();
+            postComplete();
+            return r;
+        } else if (interrupted)
+            return null;
+        else
+            throw new TimeoutException();
+    }
+
+    /* ------------- public methods -------------- */
+
+    /**
+     * Creates a new incomplete CompletableFuture.
+     */
+    public CompletableFuture() {
+    }
+
+    /**
+     * Creates a new complete CompletableFuture with given encoded result.
+     */
+    CompletableFuture(Object r) {
+        RESULT.setRelease(this, r);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} with
+     * the value obtained by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
+        return asyncSupplyStage(ASYNC_POOL, supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor with the value obtained
+     * by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
+                                                       Executor executor) {
+        return asyncSupplyStage(screenExecutor(executor), supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} after
+     * it runs the given action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable) {
+        return asyncRunStage(ASYNC_POOL, runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor after it runs the given
+     * action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable,
+                                                   Executor executor) {
+        return asyncRunStage(screenExecutor(executor), runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed with
+     * the given value.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletableFuture
+     */
+    public static <U> CompletableFuture<U> completedFuture(U value) {
+        return new CompletableFuture<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns {@code true} if completed in any fashion: normally,
+     * exceptionally, or via cancellation.
+     *
+     * @return {@code true} if completed
+     */
+    public boolean isDone() {
+        return result != null;
+    }
+
+    /**
+     * Waits if necessary for this future to complete, and then
+     * returns its result.
+     *
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     */
+    @SuppressWarnings("unchecked")
+    public T get() throws InterruptedException, ExecutionException {
+        Object r;
+        if ((r = result) == null)
+            r = waitingGet(true);
+        return (T) reportGet(r);
+    }
+
+    /**
+     * Waits if necessary for at most the given time for this future
+     * to complete, and then returns its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    @SuppressWarnings("unchecked")
+    public T get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
+        Object r;
+        if ((r = result) == null)
+            r = timedGet(nanos);
+        return (T) reportGet(r);
+    }
+
+    /**
+     * Returns the result value when complete, or throws an
+     * (unchecked) exception if completed exceptionally. To better
+     * conform with the use of common functional forms, if a
+     * computation involved in the completion of this
+     * CompletableFuture threw an exception, this method throws an
+     * (unchecked) {@link CompletionException} with the underlying
+     * exception as its cause.
+     *
+     * @return the result value
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    @SuppressWarnings("unchecked")
+    public T join() {
+        Object r;
+        if ((r = result) == null)
+            r = waitingGet(false);
+        return (T) reportJoin(r);
+    }
+
+    /**
+     * Returns the result value (or throws any encountered exception)
+     * if completed, else returns the given valueIfAbsent.
+     *
+     * @param valueIfAbsent the value to return if not completed
+     * @return the result value, if completed, else the given valueIfAbsent
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    @SuppressWarnings("unchecked")
+    public T getNow(T valueIfAbsent) {
+        Object r;
+        return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
+    }
+
+    /**
+     * If not already completed, sets the value returned by {@link
+     * #get()} and related methods to the given value.
+     *
+     * @param value the result value
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean complete(T value) {
+        boolean triggered = completeValue(value);
+        postComplete();
+        return triggered;
+    }
+
+    /**
+     * If not already completed, causes invocations of {@link #get()}
+     * and related methods to throw the given exception.
+     *
+     * @param ex the exception
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean completeExceptionally(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        boolean triggered = internalComplete(new AltResult(ex));
+        postComplete();
+        return triggered;
+    }
+
+    public <U> CompletableFuture<U> thenApply(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn, Executor executor) {
+        return uniApplyStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
+        return uniAcceptStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
+        return uniAcceptStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                   Executor executor) {
+        return uniAcceptStage(screenExecutor(executor), action);
+    }
+
+    public CompletableFuture<Void> thenRun(Runnable action) {
+        return uniRunStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action) {
+        return uniRunStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action,
+                                                Executor executor) {
+        return uniRunStage(screenExecutor(executor), action);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombine(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(null, other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
+        return biApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBoth(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(null, other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action, Executor executor) {
+        return biAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
+                                                Runnable action) {
+        return biRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action) {
+        return biRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action,
+                                                     Executor executor) {
+        return biRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> applyToEither(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(null, other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn,
+        Executor executor) {
+        return orApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public CompletableFuture<Void> acceptEither(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action,
+        Executor executor) {
+        return orAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
+                                                  Runnable action) {
+        return orRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action) {
+        return orRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action,
+                                                       Executor executor) {
+        return orRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> thenCompose(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn,
+        Executor executor) {
+        return uniComposeStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<T> whenComplete(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(null, action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
+        return uniWhenCompleteStage(screenExecutor(executor), action);
+    }
+
+    public <U> CompletableFuture<U> handle(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
+        return uniHandleStage(screenExecutor(executor), fn);
+    }
+
+    /**
+     * Returns this CompletableFuture.
+     *
+     * @return this CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture() {
+        return this;
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionally(
+        Function<Throwable, ? extends T> fn) {
+        return uniExceptionallyStage(null, fn);
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionallyAsync(
+        Function<Throwable, ? extends T> fn) {
+        return uniExceptionallyStage(defaultExecutor(), fn);
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionallyAsync(
+        Function<Throwable, ? extends T> fn, Executor executor) {
+        return uniExceptionallyStage(screenExecutor(executor), fn);
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionallyCompose(
+        Function<Throwable, ? extends CompletionStage<T>> fn) {
+        return uniComposeExceptionallyStage(null, fn);
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionallyComposeAsync(
+        Function<Throwable, ? extends CompletionStage<T>> fn) {
+        return uniComposeExceptionallyStage(defaultExecutor(), fn);
+    }
+
+    // Android-added: Override annotation to mark this as overriding from CompletionStage.
+    @Override
+    public CompletableFuture<T> exceptionallyComposeAsync(
+        Function<Throwable, ? extends CompletionStage<T>> fn,
+        Executor executor) {
+        return uniComposeExceptionallyStage(screenExecutor(executor), fn);
+    }
+
+    /* ------------- Arbitrary-arity constructions -------------- */
+
+    /**
+     * Returns a new CompletableFuture that is completed when all of
+     * the given CompletableFutures complete.  If any of the given
+     * CompletableFutures complete exceptionally, then the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  Otherwise, the results,
+     * if any, of the given CompletableFutures are not reflected in
+     * the returned CompletableFuture, but may be obtained by
+     * inspecting them individually. If no CompletableFutures are
+     * provided, returns a CompletableFuture completed with the value
+     * {@code null}.
+     *
+     * <p>Among the applications of this method is to await completion
+     * of a set of independent CompletableFutures before continuing a
+     * program, as in: {@code CompletableFuture.allOf(c1, c2,
+     * c3).join();}.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed when all of the
+     * given CompletableFutures complete
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
+        return andTree(cfs, 0, cfs.length - 1);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed when any of
+     * the given CompletableFutures complete, with the same result.
+     * Otherwise, if it completed exceptionally, the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  If no CompletableFutures
+     * are provided, returns an incomplete CompletableFuture.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed with the
+     * result or exception of any of the given CompletableFutures when
+     * one completes
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
+        int n; Object r;
+        if ((n = cfs.length) <= 1)
+            return (n == 0)
+                ? new CompletableFuture<Object>()
+                : uniCopyStage(cfs[0]);
+        for (CompletableFuture<?> cf : cfs)
+            if ((r = cf.result) != null)
+                return new CompletableFuture<Object>(encodeRelay(r));
+        cfs = cfs.clone();
+        CompletableFuture<Object> d = new CompletableFuture<>();
+        for (CompletableFuture<?> cf : cfs)
+            cf.unipush(new AnyOf(d, cf, cfs));
+        // If d was completed while we were adding completions, we should
+        // clean the stack of any sources that may have had completions
+        // pushed on their stack after d was completed.
+        if (d.result != null)
+            for (int i = 0, len = cfs.length; i < len; i++)
+                if (cfs[i].result != null)
+                    for (i++; i < len; i++)
+                        if (cfs[i].result == null)
+                            cfs[i].cleanStack();
+        return d;
+    }
+
+    /* ------------- Control and status methods -------------- */
+
+    /**
+     * If not already completed, completes this CompletableFuture with
+     * a {@link CancellationException}. Dependent CompletableFutures
+     * that have not already completed will also complete
+     * exceptionally, with a {@link CompletionException} caused by
+     * this {@code CancellationException}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in this
+     * implementation because interrupts are not used to control
+     * processing.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        boolean cancelled = (result == null) &&
+            internalComplete(new AltResult(new CancellationException()));
+        postComplete();
+        return cancelled || isCancelled();
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture was cancelled
+     * before it completed normally.
+     *
+     * @return {@code true} if this CompletableFuture was cancelled
+     * before it completed normally
+     */
+    public boolean isCancelled() {
+        Object r;
+        return ((r = result) instanceof AltResult) &&
+            (((AltResult)r).ex instanceof CancellationException);
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture completed
+     * exceptionally, in any way. Possible causes include
+     * cancellation, explicit invocation of {@code
+     * completeExceptionally}, and abrupt termination of a
+     * CompletionStage action.
+     *
+     * @return {@code true} if this CompletableFuture completed
+     * exceptionally
+     */
+    public boolean isCompletedExceptionally() {
+        Object r;
+        return ((r = result) instanceof AltResult) && r != NIL;
+    }
+
+    /**
+     * Forcibly sets or resets the value subsequently returned by
+     * method {@link #get()} and related methods, whether or not
+     * already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param value the completion value
+     */
+    public void obtrudeValue(T value) {
+        result = (value == null) ? NIL : value;
+        postComplete();
+    }
+
+    /**
+     * Forcibly causes subsequent invocations of method {@link #get()}
+     * and related methods to throw the given exception, whether or
+     * not already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param ex the exception
+     * @throws NullPointerException if the exception is null
+     */
+    public void obtrudeException(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        result = new AltResult(ex);
+        postComplete();
+    }
+
+    /**
+     * Returns the estimated number of CompletableFutures whose
+     * completions are awaiting completion of this CompletableFuture.
+     * This method is designed for use in monitoring system state, not
+     * for synchronization control.
+     *
+     * @return the number of dependent CompletableFutures
+     */
+    public int getNumberOfDependents() {
+        int count = 0;
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this CompletableFuture, as well as
+     * its completion state.  The state, in brackets, contains the
+     * String {@code "Completed Normally"} or the String {@code
+     * "Completed Exceptionally"}, or the String {@code "Not
+     * completed"} followed by the number of CompletableFutures
+     * dependent upon its completion, if any.
+     *
+     * @return a string identifying this CompletableFuture, as well as its state
+     */
+    public String toString() {
+        Object r = result;
+        int count = 0; // avoid call to getNumberOfDependents in case disabled
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return super.toString() +
+            ((r == null)
+             ? ((count == 0)
+                ? "[Not completed]"
+                : "[Not completed, " + count + " dependents]")
+             : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+                ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+                : "[Completed normally]"));
+    }
+
+    // jdk9 additions
+
+    /**
+     * Returns a new incomplete CompletableFuture of the type to be
+     * returned by a CompletionStage method. Subclasses should
+     * normally override this method to return an instance of the same
+     * class as this CompletableFuture. The default implementation
+     * returns an instance of class CompletableFuture.
+     *
+     * @param <U> the type of the value
+     * @return a new CompletableFuture
+     * @since 9
+     */
+    public <U> CompletableFuture<U> newIncompleteFuture() {
+        return new CompletableFuture<U>();
+    }
+
+    /**
+     * Returns the default Executor used for async methods that do not
+     * specify an Executor. This class uses the {@link
+     * ForkJoinPool#commonPool()} if it supports more than one
+     * parallel thread, or else an Executor using one thread per async
+     * task.  This method may be overridden in subclasses to return
+     * an Executor that provides at least one independent thread.
+     *
+     * @return the executor
+     * @since 9
+     */
+    public Executor defaultExecutor() {
+        return ASYNC_POOL;
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally. If this CompletableFuture completes exceptionally,
+     * then the returned CompletableFuture completes exceptionally
+     * with a CompletionException with this exception as cause. The
+     * behavior is equivalent to {@code thenApply(x -> x)}. This
+     * method may be useful as a form of "defensive copying", to
+     * prevent clients from completing, while still being able to
+     * arrange dependent actions.
+     *
+     * @return the new CompletableFuture
+     * @since 9
+     */
+    public CompletableFuture<T> copy() {
+        return uniCopyStage(this);
+    }
+
+    /**
+     * Returns a new CompletionStage that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally, and cannot be independently completed or otherwise
+     * used in ways not defined by the methods of interface {@link
+     * CompletionStage}.  If this CompletableFuture completes
+     * exceptionally, then the returned CompletionStage completes
+     * exceptionally with a CompletionException with this exception as
+     * cause.
+     *
+     * <p>Unless overridden by a subclass, a new non-minimal
+     * CompletableFuture with all methods available can be obtained from
+     * a minimal CompletionStage via {@link #toCompletableFuture()}.
+     * For example, completion of a minimal stage can be awaited by
+     *
+     * <pre> {@code minimalStage.toCompletableFuture().join(); }</pre>
+     *
+     * @return the new CompletionStage
+     * @since 9
+     */
+    public CompletionStage<T> minimalCompletionStage() {
+        return uniAsMinimalStage();
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of
+     * the given Supplier function invoked from an asynchronous
+     * task using the given executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return this CompletableFuture
+     * @since 9
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
+                                              Executor executor) {
+        if (supplier == null || executor == null)
+            throw new NullPointerException();
+        executor.execute(new AsyncSupply<T>(this, supplier));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of the given
+     * Supplier function invoked from an asynchronous task using the
+     * default executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @return this CompletableFuture
+     * @since 9
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) {
+        return completeAsync(supplier, defaultExecutor());
+    }
+
+    /**
+     * Exceptionally completes this CompletableFuture with
+     * a {@link TimeoutException} if not otherwise completed
+     * before the given timeout.
+     *
+     * @param timeout how long to wait before completing exceptionally
+     *        with a TimeoutException, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     */
+    public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(new Timeout(this),
+                                                     timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the given value if not
+     * otherwise completed before the given timeout.
+     *
+     * @param value the value to use upon timeout
+     * @param timeout how long to wait before completing normally
+     *        with the given value, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     */
+    public CompletableFuture<T> completeOnTimeout(T value, long timeout,
+                                                  TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(
+                                           new DelayedCompleter<T>(this, value),
+                                           timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the given base
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @param executor the base executor
+     * @return the new delayed executor
+     * @since 9
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit,
+                                           Executor executor) {
+        if (unit == null || executor == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, executor);
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the default
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @return the new delayed executor
+     * @since 9
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, ASYNC_POOL);
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed with
+     * the given value and supports only those methods in
+     * interface {@link CompletionStage}.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletionStage
+     * @since 9
+     */
+    public static <U> CompletionStage<U> completedStage(U value) {
+        return new MinimalStage<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed
+     * exceptionally with the given exception.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletableFuture
+     * @since 9
+     */
+    public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new CompletableFuture<U>(new AltResult(ex));
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed
+     * exceptionally with the given exception and supports only those
+     * methods in interface {@link CompletionStage}.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletionStage
+     * @since 9
+     */
+    public static <U> CompletionStage<U> failedStage(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new MinimalStage<U>(new AltResult(ex));
+    }
+
+    /**
+     * Singleton delay scheduler, used only for starting and
+     * cancelling tasks.
+     */
+    static final class Delayer {
+        static ScheduledFuture<?> delay(Runnable command, long delay,
+                                        TimeUnit unit) {
+            return delayer.schedule(command, delay, unit);
+        }
+
+        static final class DaemonThreadFactory implements ThreadFactory {
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(r);
+                t.setDaemon(true);
+                t.setName("CompletableFutureDelayScheduler");
+                return t;
+            }
+        }
+
+        static final ScheduledThreadPoolExecutor delayer;
+        static {
+            (delayer = new ScheduledThreadPoolExecutor(
+                1, new DaemonThreadFactory())).
+                setRemoveOnCancelPolicy(true);
+        }
+    }
+
+    // Little class-ified lambdas to better support monitoring
+
+    static final class DelayedExecutor implements Executor {
+        final long delay;
+        final TimeUnit unit;
+        final Executor executor;
+        DelayedExecutor(long delay, TimeUnit unit, Executor executor) {
+            this.delay = delay; this.unit = unit; this.executor = executor;
+        }
+        public void execute(Runnable r) {
+            Delayer.delay(new TaskSubmitter(executor, r), delay, unit);
+        }
+    }
+
+    /** Action to submit user task */
+    static final class TaskSubmitter implements Runnable {
+        final Executor executor;
+        final Runnable action;
+        TaskSubmitter(Executor executor, Runnable action) {
+            this.executor = executor;
+            this.action = action;
+        }
+        public void run() { executor.execute(action); }
+    }
+
+    /** Action to completeExceptionally on timeout */
+    static final class Timeout implements Runnable {
+        final CompletableFuture<?> f;
+        Timeout(CompletableFuture<?> f) { this.f = f; }
+        public void run() {
+            if (f != null && !f.isDone())
+                f.completeExceptionally(new TimeoutException());
+        }
+    }
+
+    /** Action to complete on timeout */
+    static final class DelayedCompleter<U> implements Runnable {
+        final CompletableFuture<U> f;
+        final U u;
+        DelayedCompleter(CompletableFuture<U> f, U u) { this.f = f; this.u = u; }
+        public void run() {
+            if (f != null)
+                f.complete(u);
+        }
+    }
+
+    /** Action to cancel unneeded timeouts */
+    static final class Canceller implements BiConsumer<Object, Throwable> {
+        final Future<?> f;
+        Canceller(Future<?> f) { this.f = f; }
+        public void accept(Object ignore, Throwable ex) {
+            if (ex == null && f != null && !f.isDone())
+                f.cancel(false);
+        }
+    }
+
+    /**
+     * A subclass that just throws UOE for most non-CompletionStage methods.
+     */
+    static final class MinimalStage<T> extends CompletableFuture<T> {
+        MinimalStage() { }
+        MinimalStage(Object r) { super(r); }
+        @Override public <U> CompletableFuture<U> newIncompleteFuture() {
+            return new MinimalStage<U>(); }
+        @Override public T get() {
+            throw new UnsupportedOperationException(); }
+        @Override public T get(long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public T getNow(T valueIfAbsent) {
+            throw new UnsupportedOperationException(); }
+        @Override public T join() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean complete(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean completeExceptionally(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean cancel(boolean mayInterruptIfRunning) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeValue(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeException(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isDone() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCancelled() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCompletedExceptionally() {
+            throw new UnsupportedOperationException(); }
+        @Override public int getNumberOfDependents() {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier, Executor executor) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> orTimeout
+            (long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeOnTimeout
+            (T value, long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> toCompletableFuture() {
+            Object r;
+            if ((r = result) != null)
+                return new CompletableFuture<T>(encodeRelay(r));
+            else {
+                CompletableFuture<T> d = new CompletableFuture<>();
+                unipush(new UniRelay<T,T>(d, this));
+                return d;
+            }
+        }
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle RESULT;
+    private static final VarHandle STACK;
+    private static final VarHandle NEXT;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class);
+            STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
+            NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/CompletionException.java b/android-35/java/util/concurrent/CompletionException.java
new file mode 100644
index 0000000..2a3cfc5
--- /dev/null
+++ b/android-35/java/util/concurrent/CompletionException.java
@@ -0,0 +1,90 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when an error or other exception is encountered
+ * in the course of completing a result or task.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class CompletionException extends RuntimeException {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs a {@code CompletionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected CompletionException() { }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected CompletionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/android-35/java/util/concurrent/CompletionService.java b/android-35/java/util/concurrent/CompletionService.java
new file mode 100644
index 0000000..5e5232e
--- /dev/null
+++ b/android-35/java/util/concurrent/CompletionService.java
@@ -0,0 +1,126 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A service that decouples the production of new asynchronous tasks
+ * from the consumption of the results of completed tasks.  Producers
+ * {@code submit} tasks for execution. Consumers {@code take}
+ * completed tasks and process their results in the order they
+ * complete.  A {@code CompletionService} can for example be used to
+ * manage asynchronous I/O, in which tasks that perform reads are
+ * submitted in one part of a program or system, and then acted upon
+ * in a different part of the program when the reads complete,
+ * possibly in a different order than they were requested.
+ *
+ * <p>Typically, a {@code CompletionService} relies on a separate
+ * {@link Executor} to actually execute the tasks, in which case the
+ * {@code CompletionService} only manages an internal completion
+ * queue. The {@link ExecutorCompletionService} class provides an
+ * implementation of this approach.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a task to a {@code CompletionService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions taken by that task, which in turn <i>happen-before</i>
+ * actions following a successful return from the corresponding {@code take()}.
+ *
+ * @since 1.5
+ */
+public interface CompletionService<V> {
+    /**
+     * Submits a value-returning task for execution and returns a Future
+     * representing the pending results of the task.  Upon completion,
+     * this task may be taken or polled.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Callable<V> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task.  Upon completion, this task may be
+     * taken or polled.
+     *
+     * @param task the task to submit
+     * @param result the result to return upon successful completion
+     * @return a Future representing pending completion of the task,
+     *         and whose {@code get()} method will return the given
+     *         result value upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Runnable task, V result);
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if none are yet present.
+     *
+     * @return the Future representing the next completed task
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, or {@code null} if none are present.
+     *
+     * @return the Future representing the next completed task, or
+     *         {@code null} if none are present
+     */
+    Future<V> poll();
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if necessary up to the specified wait
+     * time if none are yet present.
+     *
+     * @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 Future representing the next completed task or
+     *         {@code null} if the specified waiting time elapses
+     *         before one is present
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
+}
diff --git a/android-35/java/util/concurrent/CompletionStage.java b/android-35/java/util/concurrent/CompletionStage.java
new file mode 100644
index 0000000..35b44fa
--- /dev/null
+++ b/android-35/java/util/concurrent/CompletionStage.java
@@ -0,0 +1,989 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A stage of a possibly asynchronous computation, that performs an
+ * action or computes a value when another CompletionStage completes.
+ * A stage completes upon termination of its computation, but this may
+ * in turn trigger other dependent stages.  The functionality defined
+ * in this interface takes only a few basic forms, which expand out to
+ * a larger set of methods to capture a range of usage styles:
+ *
+ * <ul>
+ *
+ * <li>The computation performed by a stage may be expressed as a
+ * Function, Consumer, or Runnable (using methods with names including
+ * <em>apply</em>, <em>accept</em>, or <em>run</em>, respectively)
+ * depending on whether it requires arguments and/or produces results.
+ * For example:
+ * <pre> {@code
+ * stage.thenApply(x -> square(x))
+ *      .thenAccept(x -> System.out.print(x))
+ *      .thenRun(() -> System.out.println());}</pre>
+ *
+ * An additional form (<em>compose</em>) allows the construction of
+ * computation pipelines from functions returning completion stages.
+ *
+ * <p>Any argument to a stage's computation is the outcome of a
+ * triggering stage's computation.
+ *
+ * <li>One stage's execution may be triggered by completion of a
+ * single stage, or both of two stages, or either of two stages.
+ * Dependencies on a single stage are arranged using methods with
+ * prefix <em>then</em>. Those triggered by completion of
+ * <em>both</em> of two stages may <em>combine</em> their results or
+ * effects, using correspondingly named methods. Those triggered by
+ * <em>either</em> of two stages make no guarantees about which of the
+ * results or effects are used for the dependent stage's computation.
+ *
+ * <li>Dependencies among stages control the triggering of
+ * computations, but do not otherwise guarantee any particular
+ * ordering. Additionally, execution of a new stage's computations may
+ * be arranged in any of three ways: default execution, default
+ * asynchronous execution (using methods with suffix <em>async</em>
+ * that employ the stage's default asynchronous execution facility),
+ * or custom (via a supplied {@link Executor}).  The execution
+ * properties of default and async modes are specified by
+ * CompletionStage implementations, not this interface. Methods with
+ * explicit Executor arguments may have arbitrary execution
+ * properties, and might not even support concurrent execution, but
+ * are arranged for processing in a way that accommodates asynchrony.
+ *
+ * <li>Two method forms ({@link #handle handle} and {@link
+ * #whenComplete whenComplete}) support unconditional computation
+ * whether the triggering stage completed normally or exceptionally.
+ * Method {@link #exceptionally exceptionally} supports computation
+ * only when the triggering stage completes exceptionally, computing a
+ * replacement result, similarly to the java {@code catch} keyword.
+ * In all other cases, if a stage's computation terminates abruptly
+ * with an (unchecked) exception or error, then all dependent stages
+ * requiring its completion complete exceptionally as well, with a
+ * {@link CompletionException} holding the exception as its cause.  If
+ * a stage is dependent on <em>both</em> of two stages, and both
+ * complete exceptionally, then the CompletionException may correspond
+ * to either one of these exceptions.  If a stage is dependent on
+ * <em>either</em> of two others, and only one of them completes
+ * exceptionally, no guarantees are made about whether the dependent
+ * stage completes normally or exceptionally. In the case of method
+ * {@code whenComplete}, when the supplied action itself encounters an
+ * exception, then the stage completes exceptionally with this
+ * exception unless the source stage also completed exceptionally, in
+ * which case the exceptional completion from the source stage is
+ * given preference and propagated to the dependent stage.
+ *
+ * </ul>
+ *
+ * <p>All methods adhere to the above triggering, execution, and
+ * exceptional completion specifications (which are not repeated in
+ * individual method specifications). Additionally, while arguments
+ * used to pass a completion result (that is, for parameters of type
+ * {@code T}) for methods accepting them may be null, passing a null
+ * value for any other parameter will result in a {@link
+ * NullPointerException} being thrown.
+ *
+ * <p>Method form {@link #handle handle} is the most general way of
+ * creating a continuation stage, unconditionally performing a
+ * computation that is given both the result and exception (if any) of
+ * the triggering CompletionStage, and computing an arbitrary result.
+ * Method {@link #whenComplete whenComplete} is similar, but preserves
+ * the result of the triggering stage instead of computing a new one.
+ * Because a stage's normal result may be {@code null}, both methods
+ * should have a computation structured thus:
+ *
+ * <pre>{@code (result, exception) -> {
+ *   if (exception == null) {
+ *     // triggering stage completed normally
+ *   } else {
+ *     // triggering stage completed exceptionally
+ *   }
+ * }}</pre>
+ *
+ * <p>This interface does not define methods for initially creating,
+ * forcibly completing normally or exceptionally, probing completion
+ * status or results, or awaiting completion of a stage.
+ * Implementations of CompletionStage may provide means of achieving
+ * such effects, as appropriate.  Method {@link #toCompletableFuture}
+ * enables interoperability among different implementations of this
+ * interface by providing a common conversion type.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+public interface CompletionStage<T> {
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied function.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#map Optional.map} and
+     * {@link java.util.stream.Stream#map Stream.map}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                 Executor executor);
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRun(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using this stage's default
+     * asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using the supplied Executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action,
+                                              Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombine
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBoth
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,
+                                              Runnable action);
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action,
+                                                   Executor executor);
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEither
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEither
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,
+                                                Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#flatMap Optional.flatMap} and
+     * {@link java.util.stream.Stream#flatMap Stream.flatMap}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenCompose
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using this stage's default asynchronous execution
+     * facility.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using the supplied Executor.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handle
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using this stage's
+     * default asynchronous execution facility, with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using the
+     * supplied executor, with this stage's result and exception as
+     * arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments.  The returned
+     * stage is completed when the action returns.
+     *
+     * <p>Unlike method {@link #handle handle},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: if this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenComplete
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using this stage's
+     * default asynchronous execution facility when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using the supplied
+     * Executor when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction,Executor) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is executed with this stage's exception as the
+     * argument to the supplied function.  Otherwise, if this stage
+     * completes normally, then the returned stage also completes
+     * normally with the same value.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage if this CompletionStage completed
+     * exceptionally
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> exceptionally
+        (Function<Throwable, ? extends T> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is executed with this stage's exception as the
+     * argument to the supplied function, using this stage's default
+     * asynchronous execution facility.  Otherwise, if this stage
+     * completes normally, then the returned stage also completes
+     * normally with the same value.
+     *
+     * @implSpec The default implementation invokes {@link #handle},
+     * relaying to {@link #handleAsync} on exception, then {@link
+     * #thenCompose} for result.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage if this CompletionStage completed
+     * exceptionally
+     * @return the new CompletionStage
+     * @since 12
+     */
+    public default CompletionStage<T> exceptionallyAsync
+        (Function<Throwable, ? extends T> fn) {
+        return handle((r, ex) -> (ex == null)
+                      ? this
+                      : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1)))
+            .thenCompose(Function.identity());
+    }
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is executed with this stage's exception as the
+     * argument to the supplied function, using the supplied Executor.
+     * Otherwise, if this stage completes normally, then the returned
+     * stage also completes normally with the same value.
+     *
+     * @implSpec The default implementation invokes {@link #handle},
+     * relaying to {@link #handleAsync} on exception, then {@link
+     * #thenCompose} for result.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage if this CompletionStage completed
+     * exceptionally
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     * @since 12
+     */
+    public default CompletionStage<T> exceptionallyAsync
+        (Function<Throwable, ? extends T> fn, Executor executor) {
+        return handle((r, ex) -> (ex == null)
+                      ? this
+                      : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1), executor))
+            .thenCompose(Function.identity());
+    }
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is composed using the results of the supplied
+     * function applied to this stage's exception.
+     *
+     * @implSpec The default implementation invokes {@link #handle},
+     * invoking the given function on exception, then {@link
+     * #thenCompose} for result.
+     *
+     * @param fn the function to use to compute the returned
+     * CompletionStage if this CompletionStage completed exceptionally
+     * @return the new CompletionStage
+     * @since 12
+     */
+    public default CompletionStage<T> exceptionallyCompose
+        (Function<Throwable, ? extends CompletionStage<T>> fn) {
+        return handle((r, ex) -> (ex == null)
+                      ? this
+                      : fn.apply(ex))
+            .thenCompose(Function.identity());
+    }
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is composed using the results of the supplied
+     * function applied to this stage's exception, using this stage's
+     * default asynchronous execution facility.
+     *
+     * @implSpec The default implementation invokes {@link #handle},
+     * relaying to {@link #handleAsync} on exception, then {@link
+     * #thenCompose} for result.
+     *
+     * @param fn the function to use to compute the returned
+     * CompletionStage if this CompletionStage completed exceptionally
+     * @return the new CompletionStage
+     * @since 12
+     */
+    public default CompletionStage<T> exceptionallyComposeAsync
+        (Function<Throwable, ? extends CompletionStage<T>> fn) {
+        return handle((r, ex) -> (ex == null)
+                      ? this
+                      : this.handleAsync((r1, ex1) -> fn.apply(ex1))
+                        .thenCompose(Function.identity()))
+            .thenCompose(Function.identity());
+    }
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is composed using the results of the supplied
+     * function applied to this stage's exception, using the
+     * supplied Executor.
+     *
+     * @implSpec The default implementation invokes {@link #handle},
+     * relaying to {@link #handleAsync} on exception, then {@link
+     * #thenCompose} for result.
+     *
+     * @param fn the function to use to compute the returned
+     * CompletionStage if this CompletionStage completed exceptionally
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     * @since 12
+     */
+    public default CompletionStage<T> exceptionallyComposeAsync
+        (Function<Throwable, ? extends CompletionStage<T>> fn,
+         Executor executor) {
+        return handle((r, ex) -> (ex == null)
+                      ? this
+                      : this.handleAsync((r1, ex1) -> fn.apply(ex1), executor)
+                        .thenCompose(Function.identity()))
+            .thenCompose(Function.identity());
+    }
+
+    /**
+     * Returns a {@link CompletableFuture} maintaining the same
+     * completion properties as this stage. If this stage is already a
+     * CompletableFuture, this method may return this stage itself.
+     * Otherwise, invocation of this method may be equivalent in
+     * effect to {@code thenApply(x -> x)}, but returning an instance
+     * of type {@code CompletableFuture}.
+     *
+     * @return the CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture();
+
+}
diff --git a/android-35/java/util/concurrent/ConcurrentHashMap.java b/android-35/java/util/concurrent/ConcurrentHashMap.java
new file mode 100644
index 0000000..8e5053d
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentHashMap.java
@@ -0,0 +1,6387 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.Predicate;
+import java.util.function.ToDoubleBiFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongBiFunction;
+import java.util.function.ToLongFunction;
+import java.util.stream.Stream;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * A hash table supporting full concurrency of retrievals and
+ * high expected concurrency for updates. This class obeys the
+ * same functional specification as {@link java.util.Hashtable}, and
+ * includes versions of methods corresponding to each method of
+ * {@code Hashtable}. However, even though all operations are
+ * thread-safe, retrieval operations do <em>not</em> entail locking,
+ * and there is <em>not</em> any support for locking the entire table
+ * in a way that prevents all access.  This class is fully
+ * interoperable with {@code Hashtable} in programs that rely on its
+ * thread safety but not on its synchronization details.
+ *
+ * <p>Retrieval operations (including {@code get}) generally do not
+ * block, so may overlap with update operations (including {@code put}
+ * and {@code remove}). Retrievals reflect the results of the most
+ * recently <em>completed</em> update operations holding upon their
+ * onset. (More formally, an update operation for a given key bears a
+ * <em>happens-before</em> relation with any (non-null) retrieval for
+ * that key reporting the updated value.)  For aggregate operations
+ * such as {@code putAll} and {@code clear}, concurrent retrievals may
+ * reflect insertion or removal of only some entries.  Similarly,
+ * Iterators, Spliterators and Enumerations return elements reflecting the
+ * state of the hash table at some point at or since the creation of the
+ * iterator/enumeration.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException ConcurrentModificationException}.
+ * However, iterators are designed to be used by only one thread at a time.
+ * Bear in mind that the results of aggregate status methods including
+ * {@code size}, {@code isEmpty}, and {@code containsValue} are typically
+ * useful only when a map is not undergoing concurrent updates in other threads.
+ * Otherwise the results of these methods reflect transient states
+ * that may be adequate for monitoring or estimation purposes, but not
+ * for program control.
+ *
+ * <p>The table is dynamically expanded when there are too many
+ * collisions (i.e., keys that have distinct hash codes but fall into
+ * the same slot modulo the table size), with the expected average
+ * effect of maintaining roughly two bins per mapping (corresponding
+ * to a 0.75 load factor threshold for resizing). There may be much
+ * variance around this average as mappings are added and removed, but
+ * overall, this maintains a commonly accepted time/space tradeoff for
+ * hash tables.  However, resizing this or any other kind of hash
+ * table may be a relatively slow operation. When possible, it is a
+ * good idea to provide a size estimate as an optional {@code
+ * initialCapacity} constructor argument. An additional optional
+ * {@code loadFactor} constructor argument provides a further means of
+ * customizing initial table capacity by specifying the table density
+ * to be used in calculating the amount of space to allocate for the
+ * given number of elements.  Also, for compatibility with previous
+ * versions of this class, constructors may optionally specify an
+ * expected {@code concurrencyLevel} as an additional hint for
+ * internal sizing.  Note that using many keys with exactly the same
+ * {@code hashCode()} is a sure way to slow down performance of any
+ * hash table. To ameliorate impact, when keys are {@link Comparable},
+ * this class may use comparison order among keys to help break ties.
+ *
+ * <p>A {@link Set} projection of a ConcurrentHashMap may be created
+ * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
+ * (using {@link #keySet(Object)} when only keys are of interest, and the
+ * mapped values are (perhaps transiently) not used or all take the
+ * same mapping value.
+ *
+ * <p>A ConcurrentHashMap can be used as a scalable frequency map (a
+ * form of histogram or multiset) by using {@link
+ * java.util.concurrent.atomic.LongAdder} values and initializing via
+ * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
+ * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
+ * {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces.
+ *
+ * <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
+ * does <em>not</em> allow {@code null} to be used as a key or value.
+ *
+ * <p>ConcurrentHashMaps support a set of sequential and parallel bulk
+ * operations that, unlike most {@link Stream} methods, are designed
+ * to be safely, and often sensibly, applied even with maps that are
+ * being concurrently updated by other threads; for example, when
+ * computing a snapshot summary of the values in a shared registry.
+ * There are three kinds of operation, each with four forms, accepting
+ * functions with keys, values, entries, and (key, value) pairs as
+ * arguments and/or return values. Because the elements of a
+ * ConcurrentHashMap are not ordered in any particular way, and may be
+ * processed in different orders in different parallel executions, the
+ * correctness of supplied functions should not depend on any
+ * ordering, or on any other objects or values that may transiently
+ * change while computation is in progress; and except for forEach
+ * actions, should ideally be side-effect-free. Bulk operations on
+ * {@link Map.Entry} objects do not support method {@code setValue}.
+ *
+ * <ul>
+ * <li>forEach: Performs a given action on each element.
+ * A variant form applies a given transformation on each element
+ * before performing the action.
+ *
+ * <li>search: Returns the first available non-null result of
+ * applying a given function on each element; skipping further
+ * search when a result is found.
+ *
+ * <li>reduce: Accumulates each element.  The supplied reduction
+ * function cannot rely on ordering (more formally, it should be
+ * both associative and commutative).  There are five variants:
+ *
+ * <ul>
+ *
+ * <li>Plain reductions. (There is not a form of this method for
+ * (key, value) function arguments since there is no corresponding
+ * return type.)
+ *
+ * <li>Mapped reductions that accumulate the results of a given
+ * function applied to each element.
+ *
+ * <li>Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.
+ *
+ * </ul>
+ * </ul>
+ *
+ * <p>These bulk operations accept a {@code parallelismThreshold}
+ * argument. Methods proceed sequentially if the current map size is
+ * estimated to be less than the given threshold. Using a value of
+ * {@code Long.MAX_VALUE} suppresses all parallelism.  Using a value
+ * of {@code 1} results in maximal parallelism by partitioning into
+ * enough subtasks to fully utilize the {@link
+ * ForkJoinPool#commonPool()} that is used for all parallel
+ * computations. Normally, you would initially choose one of these
+ * extreme values, and then measure performance of using in-between
+ * values that trade off overhead versus throughput.
+ *
+ * <p>The concurrency properties of bulk operations follow
+ * from those of ConcurrentHashMap: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update.  The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent).  Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result.  To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * <p>Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * <p>Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * <p>Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * <p>Speedups for parallel compared to sequential forms are common
+ * but not guaranteed.  Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms if the
+ * underlying work to parallelize the computation is more expensive
+ * than the computation itself.  Similarly, parallelization may not
+ * lead to much actual parallelism if all processors are busy
+ * performing unrelated tasks.
+ *
+ * <p>All arguments to all task methods must be non-null.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentMap<K,V>, Serializable {
+    private static final long serialVersionUID = 7249069246763182397L;
+
+    /*
+     * Overview:
+     *
+     * The primary design goal of this hash table is to maintain
+     * concurrent readability (typically method get(), but also
+     * iterators and related methods) while minimizing update
+     * contention. Secondary goals are to keep space consumption about
+     * the same or better than java.util.HashMap, and to support high
+     * initial insertion rates on an empty table by many threads.
+     *
+     * This map usually acts as a binned (bucketed) hash table.  Each
+     * key-value mapping is held in a Node.  Most nodes are instances
+     * of the basic Node class with hash, key, value, and next
+     * fields. However, various subclasses exist: TreeNodes are
+     * arranged in balanced trees, not lists.  TreeBins hold the roots
+     * of sets of TreeNodes. ForwardingNodes are placed at the heads
+     * of bins during resizing. ReservationNodes are used as
+     * placeholders while establishing values in computeIfAbsent and
+     * related methods.  The types TreeBin, ForwardingNode, and
+     * ReservationNode do not hold normal user keys, values, or
+     * hashes, and are readily distinguishable during search etc
+     * because they have negative hash fields and null key and value
+     * fields. (These special nodes are either uncommon or transient,
+     * so the impact of carrying around some unused fields is
+     * insignificant.)
+     *
+     * The table is lazily initialized to a power-of-two size upon the
+     * first insertion.  Each bin in the table normally contains a
+     * list of Nodes (most often, the list has only zero or one Node).
+     * Table accesses require volatile/atomic reads, writes, and
+     * CASes.  Because there is no other way to arrange this without
+     * adding further indirections, we use intrinsics
+     * (jdk.internal.misc.Unsafe) operations.
+     *
+     * We use the top (sign) bit of Node hash fields for control
+     * purposes -- it is available anyway because of addressing
+     * constraints.  Nodes with negative hash fields are specially
+     * handled or ignored in map methods.
+     *
+     * Insertion (via put or its variants) of the first node in an
+     * empty bin is performed by just CASing it to the bin.  This is
+     * by far the most common case for put operations under most
+     * key/hash distributions.  Other update operations (insert,
+     * delete, and replace) require locks.  We do not want to waste
+     * the space required to associate a distinct lock object with
+     * each bin, so instead use the first node of a bin list itself as
+     * a lock. Locking support for these locks relies on builtin
+     * "synchronized" monitors.
+     *
+     * Using the first node of a list as a lock does not by itself
+     * suffice though: When a node is locked, any update must first
+     * validate that it is still the first node after locking it, and
+     * retry if not. Because new nodes are always appended to lists,
+     * once a node is first in a bin, it remains first until deleted
+     * or the bin becomes invalidated (upon resizing).
+     *
+     * The main disadvantage of per-bin locks is that other update
+     * operations on other nodes in a bin list protected by the same
+     * lock can stall, for example when user equals() or mapping
+     * functions take a long time.  However, statistically, under
+     * random hash codes, this is not a common problem.  Ideally, the
+     * frequency of nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average, given the resizing threshold
+     * of 0.75, although with a large variance because of resizing
+     * granularity. Ignoring variance, the expected occurrences of
+     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
+     * first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * Lock contention probability for two threads accessing distinct
+     * elements is roughly 1 / (8 * #elements) under random hashes.
+     *
+     * Actual hash code distributions encountered in practice
+     * sometimes deviate significantly from uniform randomness.  This
+     * includes the case when N > (1<<30), so some keys MUST collide.
+     * Similarly for dumb or hostile usages in which multiple keys are
+     * designed to have identical hash codes or ones that differs only
+     * in masked-out high bits. So we use a secondary strategy that
+     * applies when the number of nodes in a bin exceeds a
+     * threshold. These TreeBins use a balanced tree to hold nodes (a
+     * specialized form of red-black trees), bounding search time to
+     * O(log N).  Each search step in a TreeBin is at least twice as
+     * slow as in a regular list, but given that N cannot exceed
+     * (1<<64) (before running out of addresses) this bounds search
+     * steps, lock hold times, etc, to reasonable constants (roughly
+     * 100 nodes inspected per operation worst case) so long as keys
+     * are Comparable (which is very common -- String, Long, etc).
+     * TreeBin nodes (TreeNodes) also maintain the same "next"
+     * traversal pointers as regular nodes, so can be traversed in
+     * iterators in the same way.
+     *
+     * The table is resized when occupancy exceeds a percentage
+     * threshold (nominally, 0.75, but see below).  Any thread
+     * noticing an overfull bin may assist in resizing after the
+     * initiating thread allocates and sets up the replacement array.
+     * However, rather than stalling, these other threads may proceed
+     * with insertions etc.  The use of TreeBins shields us from the
+     * worst case effects of overfilling while resizes are in
+     * progress.  Resizing proceeds by transferring bins, one by one,
+     * from the table to the next table. However, threads claim small
+     * blocks of indices to transfer (via field transferIndex) before
+     * doing so, reducing contention.  A generation stamp in field
+     * sizeCtl ensures that resizings do not overlap. 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.  On average, only about one-sixth of them need
+     * cloning when a table doubles. The nodes they replace will be
+     * garbage collectible as soon as they are no longer referenced by
+     * any reader thread that may be in the midst of concurrently
+     * traversing table.  Upon transfer, the old table bin contains
+     * only a special forwarding node (with hash field "MOVED") that
+     * contains the next table as its key. On encountering a
+     * forwarding node, access and update operations restart, using
+     * the new table.
+     *
+     * Each bin transfer requires its bin lock, which can stall
+     * waiting for locks while resizing. However, because other
+     * threads can join in and help resize rather than contend for
+     * locks, average aggregate waits become shorter as resizing
+     * progresses.  The transfer operation must also ensure that all
+     * accessible bins in both the old and new table are usable by any
+     * traversal.  This is arranged in part by proceeding from the
+     * last bin (table.length - 1) up towards the first.  Upon seeing
+     * a forwarding node, traversals (see class Traverser) arrange to
+     * move to the new table without revisiting nodes.  To ensure that
+     * no intervening nodes are skipped even when moved out of order,
+     * a stack (see class TableStack) is created on first encounter of
+     * a forwarding node during a traversal, to maintain its place if
+     * later processing the current table. The need for these
+     * save/restore mechanics is relatively rare, but when one
+     * forwarding node is encountered, typically many more will be.
+     * So Traversers use a simple caching scheme to avoid creating so
+     * many new TableStack nodes. (Thanks to Peter Levart for
+     * suggesting use of a stack here.)
+     *
+     * The traversal scheme also applies to partial traversals of
+     * ranges of bins (via an alternate Traverser constructor)
+     * to support partitioned aggregate operations.  Also, read-only
+     * operations give up if ever forwarded to a null table, which
+     * provides support for shutdown-style clearing, which is also not
+     * currently implemented.
+     *
+     * Lazy table initialization minimizes footprint until first use,
+     * and also avoids resizings when the first operation is from a
+     * putAll, constructor with map argument, or deserialization.
+     * These cases attempt to override the initial capacity settings,
+     * but harmlessly fail to take effect in cases of races.
+     *
+     * The element count is maintained using a specialization of
+     * LongAdder. We need to incorporate a specialization rather than
+     * just use a LongAdder in order to access implicit
+     * contention-sensing that leads to creation of multiple
+     * CounterCells.  The counter mechanics avoid contention on
+     * updates but can encounter cache thrashing if read too
+     * frequently during concurrent access. To avoid reading so often,
+     * resizing under contention is attempted only upon adding to a
+     * bin already holding two or more nodes. Under uniform hash
+     * distributions, the probability of this occurring at threshold
+     * is around 13%, meaning that only about 1 in 8 puts check
+     * threshold (and after resizing, many fewer do so).
+     *
+     * TreeBins use a special form of comparison for search and
+     * related operations (which is the main reason we cannot use
+     * existing collections such as TreeMaps). TreeBins contain
+     * Comparable elements, but may contain others, as well as
+     * elements that are Comparable but not necessarily Comparable for
+     * the same T, so we cannot invoke compareTo among them. To handle
+     * this, the tree is ordered primarily by hash value, then by
+     * Comparable.compareTo order if applicable.  On lookup at a node,
+     * if elements are not comparable or compare as 0 then both left
+     * and right children may need to be searched in the case of tied
+     * hash values. (This corresponds to the full list search that
+     * would be necessary if all elements were non-Comparable and had
+     * tied hashes.) On insertion, to keep a total ordering (or as
+     * close as is required here) across rebalancings, we compare
+     * classes and identityHashCodes as tie-breakers. The red-black
+     * balancing code is updated from pre-jdk-collections
+     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+     * Algorithms" (CLR).
+     *
+     * TreeBins also require an additional locking mechanism.  While
+     * list traversal is always possible by readers even during
+     * updates, tree traversal is not, mainly because of tree-rotations
+     * that may change the root node and/or its linkages.  TreeBins
+     * include a simple read-write lock mechanism parasitic on the
+     * main bin-synchronization strategy: Structural adjustments
+     * associated with an insertion or removal are already bin-locked
+     * (and so cannot conflict with other writers) but must wait for
+     * ongoing readers to finish. Since there can be only one such
+     * waiter, we use a simple scheme using a single "waiter" field to
+     * block writers.  However, readers need never block.  If the root
+     * lock is held, they proceed along the slow traversal path (via
+     * next-pointers) until the lock becomes available or the list is
+     * exhausted, whichever comes first. These cases are not fast, but
+     * maximize aggregate expected throughput.
+     *
+     * Maintaining API and serialization compatibility with previous
+     * versions of this class introduces several oddities. Mainly: We
+     * leave untouched but unused constructor arguments referring to
+     * concurrencyLevel. We accept a loadFactor constructor argument,
+     * but apply it only to initial table capacity (which is the only
+     * time that we can guarantee to honor it.) We also declare an
+     * unused "Segment" class that is instantiated in minimal form
+     * only when serializing.
+     *
+     * Also, solely for compatibility with previous versions of this
+     * class, it extends AbstractMap, even though all of its methods
+     * are overridden, so it is just useless baggage.
+     *
+     * This file is organized to make things a little easier to follow
+     * while reading than they might otherwise: First the main static
+     * declarations and utilities, then fields, then main public
+     * methods (with a few factorings of multiple public methods into
+     * internal ones), then sizing methods, trees, traversers, and
+     * bulk operations.
+     */
+
+    /* ---------------- Constants -------------- */
+
+    /**
+     * The largest possible table capacity.  This value must be
+     * exactly 1<<30 to stay within Java array allocation and indexing
+     * bounds for power of two table sizes, and is further required
+     * because the top two bits of 32bit hash fields are used for
+     * control purposes.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The default initial table capacity.  Must be a power of 2
+     * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
+     */
+    private static final int DEFAULT_CAPACITY = 16;
+
+    /**
+     * The largest possible (non-power of two) array size.
+     * Needed by toArray and related methods.
+     */
+    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * The default concurrency level for this table. Unused but
+     * defined for compatibility with previous versions of this class.
+     */
+    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+
+    /**
+     * The load factor for this table. Overrides of this value in
+     * constructors affect only the initial table capacity.  The
+     * actual floating point value isn't normally used -- it is
+     * simpler to use expressions such as {@code n - (n >>> 2)} for
+     * the associated resizing threshold.
+     */
+    private static final float LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2, and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * The value should be at least 4 * TREEIFY_THRESHOLD to avoid
+     * conflicts between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Minimum number of rebinnings per transfer step. Ranges are
+     * subdivided to allow multiple resizer threads.  This value
+     * serves as a lower bound to avoid resizers encountering
+     * excessive memory contention.  The value should be at least
+     * DEFAULT_CAPACITY.
+     */
+    private static final int MIN_TRANSFER_STRIDE = 16;
+
+    /**
+     * The number of bits used for generation stamp in sizeCtl.
+     * Must be at least 6 for 32bit arrays.
+     */
+    private static final int RESIZE_STAMP_BITS = 16;
+
+    /**
+     * The maximum number of threads that can help resize.
+     * Must fit in 32 - RESIZE_STAMP_BITS bits.
+     */
+    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
+
+    /**
+     * The bit shift for recording size stamp in sizeCtl.
+     */
+    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
+
+    /*
+     * Encodings for Node hash fields. See above for explanation.
+     */
+    static final int MOVED     = -1; // hash for forwarding nodes
+    static final int TREEBIN   = -2; // hash for roots of trees
+    static final int RESERVED  = -3; // hash for transient reservations
+    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
+
+    /** Number of CPUS, to place bounds on some sizings */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Serialized pseudo-fields, provided only for jdk7 compatibility.
+     * @serialField segments Segment[]
+     *   The segments, each of which is a specialized hash table.
+     * @serialField segmentMask int
+     *   Mask value for indexing into segments. The upper bits of a
+     *   key's hash code are used to choose the segment.
+     * @serialField segmentShift int
+     *   Shift value for indexing within segments.
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("segments", Segment[].class),
+        new ObjectStreamField("segmentMask", Integer.TYPE),
+        new ObjectStreamField("segmentShift", Integer.TYPE),
+    };
+
+    /* ---------------- Nodes -------------- */
+
+    /**
+     * Key-value entry.  This class is never exported out as a
+     * user-mutable Map.Entry (i.e., one supporting setValue; see
+     * MapEntry below), but can be used for read-only traversals used
+     * in bulk tasks.  Subclasses of Node with a negative hash field
+     * are special, and contain null keys and values (but are never
+     * exported).  Otherwise, keys and vals are never null.
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        volatile V val;
+        volatile Node<K,V> next;
+
+        Node(int hash, K key, V val) {
+            this.hash = hash;
+            this.key = key;
+            this.val = val;
+        }
+
+        Node(int hash, K key, V val, Node<K,V> next) {
+            this(hash, key, val);
+            this.next = next;
+        }
+
+        public final K getKey()     { return key; }
+        public final V getValue()   { return val; }
+        public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
+        public final String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+        public final V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public final boolean equals(Object o) {
+            Object k, v, u; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == (u = val) || v.equals(u)));
+        }
+
+        /**
+         * Virtualized support for map.get(); overridden in subclasses.
+         */
+        Node<K,V> find(int h, Object k) {
+            Node<K,V> e = this;
+            if (k != null) {
+                do {
+                    K ek;
+                    if (e.hash == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Spreads (XORs) higher bits of hash to lower and also forces top
+     * bit to 0. Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int spread(int h) {
+        return (h ^ (h >>> 16)) & HASH_BITS;
+    }
+
+    /**
+     * Returns a power of two table size for the given desired capacity.
+     * See Hackers Delight, sec 3.2
+     */
+    private static final int tableSizeFor(int c) {
+        int n = -1 >>> Integer.numberOfLeadingZeros(c - 1);
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (Type t : ts) {
+                    if ((t instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /* ---------------- Table element access -------------- */
+
+    /*
+     * Atomic access methods are used for table elements as well as
+     * elements of in-progress next table while resizing.  All uses of
+     * the tab arguments must be null checked by callers.  All callers
+     * also paranoically precheck that tab's length is not zero (or an
+     * equivalent check), thus ensuring that any index argument taking
+     * the form of a hash value anded with (length - 1) is a valid
+     * index.  Note that, to be correct wrt arbitrary concurrency
+     * errors by users, these checks must operate on local variables,
+     * which accounts for some odd-looking inline assignments below.
+     * Note that calls to setTabAt always occur within locked regions,
+     * and so require only release ordering.
+     */
+
+    @SuppressWarnings("unchecked")
+    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
+        return (Node<K,V>)U.getReferenceAcquire(tab, ((long)i << ASHIFT) + ABASE);
+    }
+
+    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
+                                        Node<K,V> c, Node<K,V> v) {
+        return U.compareAndSetReference(tab, ((long)i << ASHIFT) + ABASE, c, v);
+    }
+
+    static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
+        U.putReferenceRelease(tab, ((long)i << ASHIFT) + ABASE, v);
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The array of bins. Lazily initialized upon first insertion.
+     * Size is always a power of two. Accessed directly by iterators.
+     */
+    transient volatile Node<K,V>[] table;
+
+    /**
+     * The next table to use; non-null only while resizing.
+     */
+    private transient volatile Node<K,V>[] nextTable;
+
+    /**
+     * Base counter value, used mainly when there is no contention,
+     * but also as a fallback during table initialization
+     * races. Updated via CAS.
+     */
+    private transient volatile long baseCount;
+
+    /**
+     * Table initialization and resizing control.  When negative, the
+     * table is being initialized or resized: -1 for initialization,
+     * else -(1 + the number of active resizing threads).  Otherwise,
+     * when table is null, holds the initial table size to use upon
+     * creation, or 0 for default. After initialization, holds the
+     * next element count value upon which to resize the table.
+     */
+    private transient volatile int sizeCtl;
+
+    /**
+     * The next table index (plus one) to split while resizing.
+     */
+    private transient volatile int transferIndex;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
+     */
+    private transient volatile int cellsBusy;
+
+    /**
+     * Table of counter cells. When non-null, size is a power of 2.
+     */
+    private transient volatile CounterCell[] counterCells;
+
+    // views
+    private transient KeySetView<K,V> keySet;
+    private transient ValuesView<K,V> values;
+    private transient EntrySetView<K,V> entrySet;
+
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Creates a new, empty map with the default initial table size (16).
+     */
+    public ConcurrentHashMap() {
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size
+     * accommodating the specified number of elements without the need
+     * to dynamically resize.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     */
+    public ConcurrentHashMap(int initialCapacity) {
+        this(initialCapacity, LOAD_FACTOR, 1);
+    }
+
+    /**
+     * Creates a new map with the same mappings as the given map.
+     *
+     * @param m the map
+     */
+    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
+        this.sizeCtl = DEFAULT_CAPACITY;
+        putAll(m);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}) and
+     * initial table density ({@code loadFactor}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative or the load factor is nonpositive
+     *
+     * @since 1.6
+     */
+    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
+        this(initialCapacity, loadFactor, 1);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}), initial
+     * table density ({@code loadFactor}), and number of concurrently
+     * updating threads ({@code concurrencyLevel}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @param concurrencyLevel the estimated number of concurrently
+     * updating threads. The implementation may use this value as
+     * a sizing hint.
+     * @throws IllegalArgumentException if the initial capacity is
+     * negative or the load factor or concurrencyLevel are
+     * nonpositive
+     */
+    public ConcurrentHashMap(int initialCapacity,
+                             float loadFactor, int concurrencyLevel) {
+        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
+            throw new IllegalArgumentException();
+        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
+            initialCapacity = concurrencyLevel;   // as estimated threads
+        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
+        int cap = (size >= (long)MAXIMUM_CAPACITY) ?
+            MAXIMUM_CAPACITY : tableSizeFor((int)size);
+        this.sizeCtl = cap;
+    }
+
+    // Original (since JDK1.2) Map methods
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        long n = sumCount();
+        return ((n < 0L) ? 0 :
+                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                (int)n);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return sumCount() <= 0L; // ignore transient negative values
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key.equals(k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
+        int h = spread(key.hashCode());
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (e = tabAt(tab, (n - 1) & h)) != null) {
+            if ((eh = e.hash) == h) {
+                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
+                    return e.val;
+            }
+            else if (eh < 0)
+                return (p = e.find(h, key)) != null ? p.val : null;
+            while ((e = e.next) != null) {
+                if (e.hash == h &&
+                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
+                    return e.val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tests if the specified object is a key in this table.
+     *
+     * @param  key possible key
+     * @return {@code true} if and only if the specified object
+     *         is a key in this table, as determined by the
+     *         {@code equals} method; {@code false} otherwise
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return get(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value. Note: This method may require a full traversal
+     * of the map, and is much slower than method {@code containsKey}.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V v;
+                if ((v = p.val) == value || (v != null && value.equals(v)))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Maps the specified key to the specified value in this table.
+     * Neither the key nor the value can be null.
+     *
+     * <p>The value can be retrieved by calling the {@code get} method
+     * with a key that is equal to the original key.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        return putVal(key, value, false);
+    }
+
+    /** Implementation for put and putIfAbsent */
+    final V putVal(K key, V value, boolean onlyIfAbsent) {
+        if (key == null || value == null) throw new NullPointerException();
+        int hash = spread(key.hashCode());
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh; K fk; V fv;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
+                    break;                   // no lock when adding to empty bin
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else if (onlyIfAbsent // check first node without acquiring lock
+                     && fh == hash
+                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+                     && (fv = f.val) != null)
+                return fv;
+            else {
+                V oldVal = null;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    oldVal = e.val;
+                                    if (!onlyIfAbsent)
+                                        e.val = value;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    pred.next = new Node<K,V>(hash, key, value);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            Node<K,V> p;
+                            binCount = 2;
+                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
+                                                           value)) != null) {
+                                oldVal = p.val;
+                                if (!onlyIfAbsent)
+                                    p.val = value;
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (oldVal != null)
+                        return oldVal;
+                    break;
+                }
+            }
+        }
+        addCount(1L, binCount);
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this one.
+     * These mappings replace any mappings that this map had for any of the
+     * keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        tryPresize(m.size());
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            putVal(e.getKey(), e.getValue(), false);
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this map.
+     * This method does nothing if the key is not in the map.
+     *
+     * @param  key the key that needs to be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return replaceNode(key, null, null);
+    }
+
+    /**
+     * Implementation for the four public remove/replace methods:
+     * Replaces node value with v, conditional upon match of cv if
+     * non-null.  If resulting value is null, delete.
+     */
+    final V replaceNode(Object key, V value, Object cv) {
+        int hash = spread(key.hashCode());
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0 ||
+                (f = tabAt(tab, i = (n - 1) & hash)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                V oldVal = null;
+                boolean validated = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            validated = true;
+                            for (Node<K,V> e = f, pred = null;;) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    V ev = e.val;
+                                    if (cv == null || cv == ev ||
+                                        (ev != null && cv.equals(ev))) {
+                                        oldVal = ev;
+                                        if (value != null)
+                                            e.val = value;
+                                        else if (pred != null)
+                                            pred.next = e.next;
+                                        else
+                                            setTabAt(tab, i, e.next);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            validated = true;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(hash, key, null)) != null) {
+                                V pv = p.val;
+                                if (cv == null || cv == pv ||
+                                    (pv != null && cv.equals(pv))) {
+                                    oldVal = pv;
+                                    if (value != null)
+                                        p.val = value;
+                                    else if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (validated) {
+                    if (oldVal != null) {
+                        if (value == null)
+                            addCount(-1L, -1);
+                        return oldVal;
+                    }
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        long delta = 0L; // negative number of deletions
+        int i = 0;
+        Node<K,V>[] tab = table;
+        while (tab != null && i < tab.length) {
+            int fh;
+            Node<K,V> f = tabAt(tab, i);
+            if (f == null)
+                ++i;
+            else if ((fh = f.hash) == MOVED) {
+                tab = helpTransfer(tab, f);
+                i = 0; // restart
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> p = (fh >= 0 ? f :
+                                       (f instanceof TreeBin) ?
+                                       ((TreeBin<K,V>)f).first : null);
+                        while (p != null) {
+                            --delta;
+                            p = p.next;
+                        }
+                        setTabAt(tab, i++, null);
+                    }
+                }
+            }
+        }
+        if (delta != 0L)
+            addCount(delta, -1);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa. The set supports element
+     * removal, which removes the corresponding mapping from this map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p> The set returned by this method is guaranteed to an instance of
+     * {@link KeySetView}.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    // Android-changed: Return type for backwards compat. Was KeySetView<K,V>. http://b/28099367
+    @dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
+    public Set<K> keySet() {
+        KeySetView<K,V> ks;
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySetView<K,V>(this, null);
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from this map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll}, and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}
+     * and {@link Spliterator#NONNULL}.
+     *
+     * @return the collection view
+     */
+    public Collection<V> values() {
+        ValuesView<K,V> vs;
+        if ((vs = values) != null) return vs;
+        return values = new ValuesView<K,V>(this);
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySetView<K,V> es;
+        if ((es = entrySet) != null) return es;
+        return entrySet = new EntrySetView<K,V>(this);
+    }
+
+    /**
+     * Returns the hash code value for this {@link Map}, i.e.,
+     * the sum of, for each key-value pair in the map,
+     * {@code key.hashCode() ^ value.hashCode()}.
+     *
+     * @return the hash code value for this map
+     */
+    public int hashCode() {
+        int h = 0;
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; )
+                h += p.key.hashCode() ^ p.val.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string
+     * representation consists of a list of key-value mappings (in no
+     * particular order) enclosed in braces ("{@code {}}").  Adjacent
+     * mappings are separated by the characters {@code ", "} (comma
+     * and space).  Each key-value mapping is rendered as the key
+     * followed by an equals sign ("{@code =}") followed by the
+     * associated value.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        Node<K,V> p;
+        if ((p = it.advance()) != null) {
+            for (;;) {
+                K k = p.key;
+                V v = p.val;
+                sb.append(k == this ? "(this Map)" : k);
+                sb.append('=');
+                sb.append(v == this ? "(this Map)" : v);
+                if ((p = it.advance()) == null)
+                    break;
+                sb.append(',').append(' ');
+            }
+        }
+        return sb.append('}').toString();
+    }
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is a map with the same
+     * mappings as this map.  This operation may return misleading
+     * results if either map is concurrently modified during execution
+     * of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o != this) {
+            if (!(o instanceof Map))
+                return false;
+            Map<?,?> m = (Map<?,?>) o;
+            Node<K,V>[] t;
+            int f = (t = table) == null ? 0 : t.length;
+            Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V val = p.val;
+                Object v = m.get(p.key);
+                if (v == null || (v != val && !v.equals(val)))
+                    return false;
+            }
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object mk, mv, v;
+                if ((mk = e.getKey()) == null ||
+                    (mv = e.getValue()) == null ||
+                    (v = get(mk)) == null ||
+                    (mv != v && !mv.equals(v)))
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Stripped-down version of helper class used in previous version,
+     * declared for the sake of serialization compatibility.
+     */
+    static class Segment<K,V> extends ReentrantLock implements Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        final float loadFactor;
+        Segment(float lf) { this.loadFactor = lf; }
+    }
+
+    /**
+     * Saves this map to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData
+     * the serialized fields, followed by 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 java.io.IOException {
+        // For serialization compatibility
+        // Emulate segment calculation from previous version of this class
+        int sshift = 0;
+        int ssize = 1;
+        while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
+            ++sshift;
+            ssize <<= 1;
+        }
+        int segmentShift = 32 - sshift;
+        int segmentMask = ssize - 1;
+        @SuppressWarnings("unchecked")
+        Segment<K,V>[] segments = (Segment<K,V>[])
+            new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
+        for (int i = 0; i < segments.length; ++i)
+            segments[i] = new Segment<K,V>(LOAD_FACTOR);
+        java.io.ObjectOutputStream.PutField streamFields = s.putFields();
+        streamFields.put("segments", segments);
+        streamFields.put("segmentShift", segmentShift);
+        streamFields.put("segmentMask", segmentMask);
+        s.writeFields();
+
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                s.writeObject(p.key);
+                s.writeObject(p.val);
+            }
+        }
+        s.writeObject(null);
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this map from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        /*
+         * To improve performance in typical cases, we create nodes
+         * while reading, then place in table once size is known.
+         * However, we must also validate uniqueness and deal with
+         * overpopulated bins while doing so, which requires
+         * specialized versions of putVal mechanics.
+         */
+        sizeCtl = -1; // force exclusion for table construction
+        s.defaultReadObject();
+        long size = 0L;
+        Node<K,V> p = null;
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            K k = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+            V v = (V) s.readObject();
+            if (k != null && v != null) {
+                p = new Node<K,V>(spread(k.hashCode()), k, v, p);
+                ++size;
+            }
+            else
+                break;
+        }
+        if (size == 0L)
+            sizeCtl = 0;
+        else {
+            long ts = (long)(1.0 + size / LOAD_FACTOR);
+            int n = (ts >= (long)MAXIMUM_CAPACITY) ?
+                MAXIMUM_CAPACITY : tableSizeFor((int)ts);
+            @SuppressWarnings("unchecked")
+            Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
+            int mask = n - 1;
+            long added = 0L;
+            while (p != null) {
+                boolean insertAtFront;
+                Node<K,V> next = p.next, first;
+                int h = p.hash, j = h & mask;
+                if ((first = tabAt(tab, j)) == null)
+                    insertAtFront = true;
+                else {
+                    K k = p.key;
+                    if (first.hash < 0) {
+                        TreeBin<K,V> t = (TreeBin<K,V>)first;
+                        if (t.putTreeVal(h, k, p.val) == null)
+                            ++added;
+                        insertAtFront = false;
+                    }
+                    else {
+                        int binCount = 0;
+                        insertAtFront = true;
+                        Node<K,V> q; K qk;
+                        for (q = first; q != null; q = q.next) {
+                            if (q.hash == h &&
+                                ((qk = q.key) == k ||
+                                 (qk != null && k.equals(qk)))) {
+                                insertAtFront = false;
+                                break;
+                            }
+                            ++binCount;
+                        }
+                        if (insertAtFront && binCount >= TREEIFY_THRESHOLD) {
+                            insertAtFront = false;
+                            ++added;
+                            p.next = first;
+                            TreeNode<K,V> hd = null, tl = null;
+                            for (q = p; q != null; q = q.next) {
+                                TreeNode<K,V> t = new TreeNode<K,V>
+                                    (q.hash, q.key, q.val, null, null);
+                                if ((t.prev = tl) == null)
+                                    hd = t;
+                                else
+                                    tl.next = t;
+                                tl = t;
+                            }
+                            setTabAt(tab, j, new TreeBin<K,V>(hd));
+                        }
+                    }
+                }
+                if (insertAtFront) {
+                    ++added;
+                    p.next = first;
+                    setTabAt(tab, j, p);
+                }
+                p = next;
+            }
+            table = tab;
+            sizeCtl = n - (n >>> 2);
+            baseCount = added;
+        }
+    }
+
+    // ConcurrentMap methods
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        return putVal(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && replaceNode(key, null, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        return replaceNode(key, newValue, oldValue) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        return replaceNode(key, value, null);
+    }
+
+    // Overrides of JDK8+ Map extension method defaults
+
+    /**
+     * Returns the value to which the specified key is mapped, or the
+     * given default value if this map contains no mapping for the
+     * key.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the default value
+     * @throws NullPointerException if the specified key is null
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = get(key)) == null ? defaultValue : v;
+    }
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                action.accept(p.key, p.val);
+            }
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V oldValue = p.val;
+                for (K key = p.key;;) {
+                    V newValue = function.apply(key, oldValue);
+                    if (newValue == null)
+                        throw new NullPointerException();
+                    if (replaceNode(key, newValue, oldValue) != null ||
+                        (oldValue = get(key)) == null)
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySetView.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for ValuesView.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                if (function.test(v) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The entire
+     * method invocation is performed atomically.  The supplied
+     * function is invoked exactly once per invocation of this method
+     * if the key is absent, else not at all.  Some attempted update
+     * operations on this map by other threads may be blocked while
+     * computation is in progress, so the computation should be short
+     * and simple.
+     *
+     * <p>The mapping function must not modify this map during computation.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key or mappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the mappingFunction does so,
+     *         in which case the mapping is left unestablished
+     */
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh; K fk; V fv;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = mappingFunction.apply(key)) != null)
+                                node = new Node<K,V>(h, key, val);
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else if (fh == h    // check first node without acquiring lock
+                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
+                     && (fv = f.val) != null)
+                return fv;
+            else {
+                boolean added = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = e.val;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    if ((val = mappingFunction.apply(key)) != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        added = true;
+                                        pred.next = new Node<K,V>(h, key, val);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null)
+                                val = p.val;
+                            else if ((val = mappingFunction.apply(key)) != null) {
+                                added = true;
+                                t.putTreeVal(h, key, val);
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (!added)
+                        return val;
+                    break;
+                }
+            }
+        }
+        if (val != null)
+            addCount(1L, binCount);
+        return val;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value.  The entire method invocation is performed atomically.
+     * The supplied function is invoked exactly once per invocation of
+     * this method if the key is present, else not at all.  Some
+     * attempted update operations on this map by other threads may be
+     * blocked while computation is in progress, so the computation
+     * should be short and simple.
+     *
+     * <p>The remapping function must not modify this map during computation.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null) {
+                                val = remappingFunction.apply(key, p.val);
+                                if (val != null)
+                                    p.val = val;
+                                else {
+                                    delta = -1;
+                                    if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The entire method invocation is performed atomically.
+     * The supplied function is invoked exactly once per invocation of
+     * this method.  Some attempted update operations on this map by
+     * other threads may be blocked while computation is in progress,
+     * so the computation should be short and simple.
+     *
+     * <p>The remapping function must not modify this map during computation.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = remappingFunction.apply(key, null)) != null) {
+                                delta = 1;
+                                node = new Node<K,V>(h, key, val);
+                            }
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    val = remappingFunction.apply(key, null);
+                                    if (val != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        delta = 1;
+                                        pred.next = new Node<K,V>(h, key, val);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 1;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null)
+                                p = r.findTreeNode(h, key, null);
+                            else
+                                p = null;
+                            V pv = (p == null) ? null : p.val;
+                            val = remappingFunction.apply(key, pv);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * If the specified key is not already associated with a
+     * (non-null) value, associates it with the given value.
+     * Otherwise, replaces the value with the results of the given
+     * remapping function, or removes if {@code null}. The entire
+     * method invocation is performed atomically.  Some attempted
+     * update operations on this map by other threads may be blocked
+     * while computation is in progress, so the computation should be
+     * short and simple, and must not attempt to update any other
+     * mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or the
+     *         remappingFunction is null
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value))) {
+                    delta = 1;
+                    val = value;
+                    break;
+                }
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(e.val, value);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    delta = 1;
+                                    val = value;
+                                    pred.next = new Node<K,V>(h, key, val);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r = t.root;
+                            TreeNode<K,V> p = (r == null) ? null :
+                                r.findTreeNode(h, key, null);
+                            val = (p == null) ? value :
+                                remappingFunction.apply(p.val, value);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    // Hashtable legacy methods
+
+    /**
+     * Tests if some key maps into the specified value in this table.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue(Object)}, and exists solely to ensure
+     * 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 {@code true} if and only if some key maps to the
+     *         {@code value} argument in this table as
+     *         determined by the {@code equals} method;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean contains(Object value) {
+        return containsValue(value);
+    }
+
+    /**
+     * Returns an enumeration of the keys in this table.
+     *
+     * @return an enumeration of the keys in this table
+     * @see #keySet()
+     */
+    public Enumeration<K> keys() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new KeyIterator<K,V>(t, f, 0, f, this);
+    }
+
+    /**
+     * Returns an enumeration of the values in this table.
+     *
+     * @return an enumeration of the values in this table
+     * @see #values()
+     */
+    public Enumeration<V> elements() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new ValueIterator<K,V>(t, f, 0, f, this);
+    }
+
+    // ConcurrentHashMap-only methods
+
+    /**
+     * Returns the number of mappings. This method should be used
+     * instead of {@link #size} because a ConcurrentHashMap may
+     * contain more mappings than can be represented as an int. The
+     * value returned is an estimate; the actual count may differ if
+     * there are concurrent insertions or removals.
+     *
+     * @return the number of mappings
+     * @since 1.8
+     */
+    public long mappingCount() {
+        long n = sumCount();
+        return (n < 0L) ? 0L : n; // ignore transient negative values
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet() {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys in this map, using the
+     * given common mapped value for any additions (i.e., {@link
+     * Collection#add} and {@link Collection#addAll(Collection)}).
+     * This is of course only appropriate if it is acceptable to use
+     * the same value for all additions from this view.
+     *
+     * @param mappedValue the mapped value to use for any additions
+     * @return the set view
+     * @throws NullPointerException if the mappedValue is null
+     */
+    public KeySetView<K,V> keySet(V mappedValue) {
+        if (mappedValue == null)
+            throw new NullPointerException();
+        return new KeySetView<K,V>(this, mappedValue);
+    }
+
+    /* ---------------- Special Nodes -------------- */
+
+    /**
+     * A node inserted at head of bins during transfer operations.
+     */
+    static final class ForwardingNode<K,V> extends Node<K,V> {
+        final Node<K,V>[] nextTable;
+        ForwardingNode(Node<K,V>[] tab) {
+            super(MOVED, null, null);
+            this.nextTable = tab;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            // loop to avoid arbitrarily deep recursion on forwarding nodes
+            outer: for (Node<K,V>[] tab = nextTable;;) {
+                Node<K,V> e; int n;
+                if (k == null || tab == null || (n = tab.length) == 0 ||
+                    (e = tabAt(tab, (n - 1) & h)) == null)
+                    return null;
+                for (;;) {
+                    int eh; K ek;
+                    if ((eh = e.hash) == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                    if (eh < 0) {
+                        if (e instanceof ForwardingNode) {
+                            tab = ((ForwardingNode<K,V>)e).nextTable;
+                            continue outer;
+                        }
+                        else
+                            return e.find(h, k);
+                    }
+                    if ((e = e.next) == null)
+                        return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * A place-holder node used in computeIfAbsent and compute.
+     */
+    static final class ReservationNode<K,V> extends Node<K,V> {
+        ReservationNode() {
+            super(RESERVED, null, null);
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return null;
+        }
+    }
+
+    /* ---------------- Table Initialization and Resizing -------------- */
+
+    /**
+     * Returns the stamp bits for resizing a table of size n.
+     * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
+     */
+    static final int resizeStamp(int n) {
+        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
+    }
+
+    /**
+     * Initializes table, using the size recorded in sizeCtl.
+     */
+    private final Node<K,V>[] initTable() {
+        Node<K,V>[] tab; int sc;
+        while ((tab = table) == null || tab.length == 0) {
+            if ((sc = sizeCtl) < 0)
+                Thread.yield(); // lost initialization race; just spin
+            else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
+                try {
+                    if ((tab = table) == null || tab.length == 0) {
+                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
+                        @SuppressWarnings("unchecked")
+                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                        table = tab = nt;
+                        sc = n - (n >>> 2);
+                    }
+                } finally {
+                    sizeCtl = sc;
+                }
+                break;
+            }
+        }
+        return tab;
+    }
+
+    /**
+     * Adds to count, and if table is too small and not already
+     * resizing, initiates transfer. If already resizing, helps
+     * perform transfer if work is available.  Rechecks occupancy
+     * after a transfer to see if another resize is already needed
+     * because resizings are lagging additions.
+     *
+     * @param x the count to add
+     * @param check if <0, don't check resize, if <= 1 only check if uncontended
+     */
+    private final void addCount(long x, int check) {
+        CounterCell[] cs; long b, s;
+        if ((cs = counterCells) != null ||
+            !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            CounterCell c; long v; int m;
+            boolean uncontended = true;
+            if (cs == null || (m = cs.length - 1) < 0 ||
+                (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
+                !(uncontended =
+                  U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
+                fullAddCount(x, uncontended);
+                return;
+            }
+            if (check <= 1)
+                return;
+            s = sumCount();
+        }
+        if (check >= 0) {
+            Node<K,V>[] tab, nt; int n, sc;
+            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
+                   (n = tab.length) < MAXIMUM_CAPACITY) {
+                int rs = resizeStamp(n) << RESIZE_STAMP_SHIFT;
+                if (sc < 0) {
+                    if (sc == rs + MAX_RESIZERS || sc == rs + 1 ||
+                        (nt = nextTable) == null || transferIndex <= 0)
+                        break;
+                    if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
+                        transfer(tab, nt);
+                }
+                else if (U.compareAndSetInt(this, SIZECTL, sc, rs + 2))
+                    transfer(tab, null);
+                s = sumCount();
+            }
+        }
+    }
+
+    /**
+     * Helps transfer if a resize is in progress.
+     */
+    final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
+        Node<K,V>[] nextTab; int sc;
+        if (tab != null && (f instanceof ForwardingNode) &&
+            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
+            int rs = resizeStamp(tab.length) << RESIZE_STAMP_SHIFT;
+            while (nextTab == nextTable && table == tab &&
+                   (sc = sizeCtl) < 0) {
+                if (sc == rs + MAX_RESIZERS || sc == rs + 1 ||
+                    transferIndex <= 0)
+                    break;
+                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
+                    transfer(tab, nextTab);
+                    break;
+                }
+            }
+            return nextTab;
+        }
+        return table;
+    }
+
+    /**
+     * Tries to presize table to accommodate the given number of elements.
+     *
+     * @param size number of elements (doesn't need to be perfectly accurate)
+     */
+    private final void tryPresize(int size) {
+        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
+            tableSizeFor(size + (size >>> 1) + 1);
+        int sc;
+        while ((sc = sizeCtl) >= 0) {
+            Node<K,V>[] tab = table; int n;
+            if (tab == null || (n = tab.length) == 0) {
+                n = (sc > c) ? sc : c;
+                if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
+                    try {
+                        if (table == tab) {
+                            @SuppressWarnings("unchecked")
+                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                            table = nt;
+                            sc = n - (n >>> 2);
+                        }
+                    } finally {
+                        sizeCtl = sc;
+                    }
+                }
+            }
+            else if (c <= sc || n >= MAXIMUM_CAPACITY)
+                break;
+            else if (tab == table) {
+                int rs = resizeStamp(n);
+                if (U.compareAndSetInt(this, SIZECTL, sc,
+                                        (rs << RESIZE_STAMP_SHIFT) + 2))
+                    transfer(tab, null);
+            }
+        }
+    }
+
+    /**
+     * Moves and/or copies the nodes in each bin to new table. See
+     * above for explanation.
+     */
+    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
+        int n = tab.length, stride;
+        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
+            stride = MIN_TRANSFER_STRIDE; // subdivide range
+        if (nextTab == null) {            // initiating
+            try {
+                @SuppressWarnings("unchecked")
+                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
+                nextTab = nt;
+            } catch (Throwable ex) {      // try to cope with OOME
+                sizeCtl = Integer.MAX_VALUE;
+                return;
+            }
+            nextTable = nextTab;
+            transferIndex = n;
+        }
+        int nextn = nextTab.length;
+        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
+        boolean advance = true;
+        boolean finishing = false; // to ensure sweep before committing nextTab
+        for (int i = 0, bound = 0;;) {
+            Node<K,V> f; int fh;
+            while (advance) {
+                int nextIndex, nextBound;
+                if (--i >= bound || finishing)
+                    advance = false;
+                else if ((nextIndex = transferIndex) <= 0) {
+                    i = -1;
+                    advance = false;
+                }
+                else if (U.compareAndSetInt
+                         (this, TRANSFERINDEX, nextIndex,
+                          nextBound = (nextIndex > stride ?
+                                       nextIndex - stride : 0))) {
+                    bound = nextBound;
+                    i = nextIndex - 1;
+                    advance = false;
+                }
+            }
+            if (i < 0 || i >= n || i + n >= nextn) {
+                int sc;
+                if (finishing) {
+                    nextTable = null;
+                    table = nextTab;
+                    sizeCtl = (n << 1) - (n >>> 1);
+                    return;
+                }
+                if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
+                        return;
+                    finishing = advance = true;
+                    i = n; // recheck before commit
+                }
+            }
+            else if ((f = tabAt(tab, i)) == null)
+                advance = casTabAt(tab, i, null, fwd);
+            else if ((fh = f.hash) == MOVED)
+                advance = true; // already processed
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> ln, hn;
+                        if (fh >= 0) {
+                            int runBit = fh & n;
+                            Node<K,V> lastRun = f;
+                            for (Node<K,V> p = f.next; p != null; p = p.next) {
+                                int b = p.hash & n;
+                                if (b != runBit) {
+                                    runBit = b;
+                                    lastRun = p;
+                                }
+                            }
+                            if (runBit == 0) {
+                                ln = lastRun;
+                                hn = null;
+                            }
+                            else {
+                                hn = lastRun;
+                                ln = null;
+                            }
+                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
+                                int ph = p.hash; K pk = p.key; V pv = p.val;
+                                if ((ph & n) == 0)
+                                    ln = new Node<K,V>(ph, pk, pv, ln);
+                                else
+                                    hn = new Node<K,V>(ph, pk, pv, hn);
+                            }
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                        else if (f instanceof TreeBin) {
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> lo = null, loTail = null;
+                            TreeNode<K,V> hi = null, hiTail = null;
+                            int lc = 0, hc = 0;
+                            for (Node<K,V> e = t.first; e != null; e = e.next) {
+                                int h = e.hash;
+                                TreeNode<K,V> p = new TreeNode<K,V>
+                                    (h, e.key, e.val, null, null);
+                                if ((h & n) == 0) {
+                                    if ((p.prev = loTail) == null)
+                                        lo = p;
+                                    else
+                                        loTail.next = p;
+                                    loTail = p;
+                                    ++lc;
+                                }
+                                else {
+                                    if ((p.prev = hiTail) == null)
+                                        hi = p;
+                                    else
+                                        hiTail.next = p;
+                                    hiTail = p;
+                                    ++hc;
+                                }
+                            }
+                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
+                                (hc != 0) ? new TreeBin<K,V>(lo) : t;
+                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
+                                (lc != 0) ? new TreeBin<K,V>(hi) : t;
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+            }
+        }
+    }
+
+    /* ---------------- Counter support -------------- */
+
+    /**
+     * A padded cell for distributing counts.  Adapted from LongAdder
+     * and Striped64.  See their internal docs for explanation.
+     */
+    @jdk.internal.vm.annotation.Contended
+    static final class CounterCell {
+        volatile long value;
+        CounterCell(long x) { value = x; }
+    }
+
+    final long sumCount() {
+        CounterCell[] cs = counterCells;
+        long sum = baseCount;
+        if (cs != null) {
+            for (CounterCell c : cs)
+                if (c != null)
+                    sum += c.value;
+        }
+        return sum;
+    }
+
+    // See LongAdder version for explanation
+    private final void fullAddCount(long x, boolean wasUncontended) {
+        int h;
+        if ((h = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();      // force initialization
+            h = ThreadLocalRandom.getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        for (;;) {
+            CounterCell[] cs; CounterCell c; int n; long v;
+            if ((cs = counterCells) != null && (n = cs.length) > 0) {
+                if ((c = cs[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {            // Try to attach new Cell
+                        CounterCell r = new CounterCell(x); // Optimistic create
+                        if (cellsBusy == 0 &&
+                            U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+                            boolean created = false;
+                            try {               // Recheck under lock
+                                CounterCell[] rs; int m, j;
+                                if ((rs = counterCells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    created = true;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            if (created)
+                                break;
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
+                    break;
+                else if (counterCells != cs || n >= NCPU)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 &&
+                         U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+                    try {
+                        if (counterCells == cs) // Expand table unless stale
+                            counterCells = Arrays.copyOf(cs, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = ThreadLocalRandom.advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && counterCells == cs &&
+                     U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
+                boolean init = false;
+                try {                           // Initialize table
+                    if (counterCells == cs) {
+                        CounterCell[] rs = new CounterCell[2];
+                        rs[h & 1] = new CounterCell(x);
+                        counterCells = rs;
+                        init = true;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+                if (init)
+                    break;
+            }
+            else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
+                break;                          // Fall back on using base
+        }
+    }
+
+    /* ---------------- Conversion from/to TreeBins -------------- */
+
+    /**
+     * Replaces all linked nodes in bin at given index unless table is
+     * too small, in which case resizes instead.
+     */
+    private final void treeifyBin(Node<K,V>[] tab, int index) {
+        Node<K,V> b; int n;
+        if (tab != null) {
+            if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
+                tryPresize(n << 1);
+            else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
+                synchronized (b) {
+                    if (tabAt(tab, index) == b) {
+                        TreeNode<K,V> hd = null, tl = null;
+                        for (Node<K,V> e = b; e != null; e = e.next) {
+                            TreeNode<K,V> p =
+                                new TreeNode<K,V>(e.hash, e.key, e.val,
+                                                  null, null);
+                            if ((p.prev = tl) == null)
+                                hd = p;
+                            else
+                                tl.next = p;
+                            tl = p;
+                        }
+                        setTabAt(tab, index, new TreeBin<K,V>(hd));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a list of non-TreeNodes replacing those in given list.
+     */
+    static <K,V> Node<K,V> untreeify(Node<K,V> b) {
+        Node<K,V> hd = null, tl = null;
+        for (Node<K,V> q = b; q != null; q = q.next) {
+            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val);
+            if (tl == null)
+                hd = p;
+            else
+                tl.next = p;
+            tl = p;
+        }
+        return hd;
+    }
+
+    /* ---------------- TreeNodes -------------- */
+
+    /**
+     * Nodes for use in TreeBins.
+     */
+    static final class TreeNode<K,V> extends Node<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+
+        TreeNode(int hash, K key, V val, Node<K,V> next,
+                 TreeNode<K,V> parent) {
+            super(hash, key, val, next);
+            this.parent = parent;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return findTreeNode(h, k, null);
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given key
+         * starting at given root.
+         */
+        final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
+            if (k != null) {
+                TreeNode<K,V> p = this;
+                do {
+                    int ph, dir; K pk; TreeNode<K,V> q;
+                    TreeNode<K,V> pl = p.left, pr = p.right;
+                    if ((ph = p.hash) > h)
+                        p = pl;
+                    else if (ph < h)
+                        p = pr;
+                    else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                        return p;
+                    else if (pl == null)
+                        p = pr;
+                    else if (pr == null)
+                        p = pl;
+                    else if ((kc != null ||
+                              (kc = comparableClassFor(k)) != null) &&
+                             (dir = compareComparables(kc, k, pk)) != 0)
+                        p = (dir < 0) ? pl : pr;
+                    else if ((q = pr.findTreeNode(h, k, kc)) != null)
+                        return q;
+                    else
+                        p = pl;
+                } while (p != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- TreeBins -------------- */
+
+    /**
+     * TreeNodes used at the heads of bins. TreeBins do not hold user
+     * keys or values, but instead point to list of TreeNodes and
+     * their root. They also maintain a parasitic read-write lock
+     * forcing writers (who hold bin lock) to wait for readers (who do
+     * not) to complete before tree restructuring operations.
+     */
+    static final class TreeBin<K,V> extends Node<K,V> {
+        TreeNode<K,V> root;
+        volatile TreeNode<K,V> first;
+        volatile Thread waiter;
+        volatile int lockState;
+        // values for lockState
+        static final int WRITER = 1; // set while holding write lock
+        static final int WAITER = 2; // set when waiting for write lock
+        static final int READER = 4; // increment value for setting read lock
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Creates bin with initial set of nodes headed by b.
+         */
+        TreeBin(TreeNode<K,V> b) {
+            super(TREEBIN, null, null);
+            this.first = b;
+            TreeNode<K,V> r = null;
+            for (TreeNode<K,V> x = b, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (r == null) {
+                    x.parent = null;
+                    x.red = false;
+                    r = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = r;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            r = balanceInsertion(r, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            this.root = r;
+            assert checkInvariants(root);
+        }
+
+        /**
+         * Acquires write lock for tree restructuring.
+         */
+        private final void lockRoot() {
+            if (!U.compareAndSetInt(this, LOCKSTATE, 0, WRITER))
+                contendedLock(); // offload to separate method
+        }
+
+        /**
+         * Releases write lock for tree restructuring.
+         */
+        private final void unlockRoot() {
+            lockState = 0;
+        }
+
+        /**
+         * Possibly blocks awaiting root lock.
+         */
+        private final void contendedLock() {
+            boolean waiting = false;
+            for (int s;;) {
+                if (((s = lockState) & ~WAITER) == 0) {
+                    if (U.compareAndSetInt(this, LOCKSTATE, s, WRITER)) {
+                        if (waiting)
+                            waiter = null;
+                        return;
+                    }
+                }
+                else if ((s & WAITER) == 0) {
+                    if (U.compareAndSetInt(this, LOCKSTATE, s, s | WAITER)) {
+                        waiting = true;
+                        waiter = Thread.currentThread();
+                    }
+                }
+                else if (waiting)
+                    LockSupport.park(this);
+            }
+        }
+
+        /**
+         * Returns matching node or null if none. Tries to search
+         * using tree comparisons from root, but continues linear
+         * search when lock not available.
+         */
+        final Node<K,V> find(int h, Object k) {
+            if (k != null) {
+                for (Node<K,V> e = first; e != null; ) {
+                    int s; K ek;
+                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
+                        if (e.hash == h &&
+                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                            return e;
+                        e = e.next;
+                    }
+                    else if (U.compareAndSetInt(this, LOCKSTATE, s,
+                                                 s + READER)) {
+                        TreeNode<K,V> r, p;
+                        try {
+                            p = ((r = root) == null ? null :
+                                 r.findTreeNode(h, k, null));
+                        } finally {
+                            Thread w;
+                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
+                                (READER|WAITER) && (w = waiter) != null)
+                                LockSupport.unpark(w);
+                        }
+                        return p;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Finds or adds a node.
+         * @return null if added
+         */
+        final TreeNode<K,V> putTreeVal(int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if (p == null) {
+                    first = root = new TreeNode<K,V>(h, k, v, null, null);
+                    break;
+                }
+                else if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    TreeNode<K,V> x, f = first;
+                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
+                    if (f != null)
+                        f.prev = x;
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    if (!xp.red)
+                        x.red = true;
+                    else {
+                        lockRoot();
+                        try {
+                            root = balanceInsertion(root, x);
+                        } finally {
+                            unlockRoot();
+                        }
+                    }
+                    break;
+                }
+            }
+            assert checkInvariants(root);
+            return null;
+        }
+
+        /**
+         * Removes the given node, that must be present before this
+         * call.  This is messier than typical red-black deletion code
+         * because we cannot swap the contents of an interior node
+         * with a leaf successor that is pinned by "next" pointers
+         * that are accessible independently of lock. So instead we
+         * swap the tree linkages.
+         *
+         * @return true if now too small, so should be untreeified
+         */
+        final boolean removeTreeNode(TreeNode<K,V> p) {
+            TreeNode<K,V> next = (TreeNode<K,V>)p.next;
+            TreeNode<K,V> pred = p.prev;  // unlink traversal pointers
+            TreeNode<K,V> r, rl;
+            if (pred == null)
+                first = next;
+            else
+                pred.next = next;
+            if (next != null)
+                next.prev = pred;
+            if (first == null) {
+                root = null;
+                return true;
+            }
+            if ((r = root) == null || r.right == null || // too small
+                (rl = r.left) == null || rl.left == null)
+                return true;
+            lockRoot();
+            try {
+                TreeNode<K,V> replacement;
+                TreeNode<K,V> pl = p.left;
+                TreeNode<K,V> pr = p.right;
+                if (pl != null && pr != null) {
+                    TreeNode<K,V> s = pr, sl;
+                    while ((sl = s.left) != null) // find successor
+                        s = sl;
+                    boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                    TreeNode<K,V> sr = s.right;
+                    TreeNode<K,V> pp = p.parent;
+                    if (s == pr) { // p was s's direct parent
+                        p.parent = s;
+                        s.right = p;
+                    }
+                    else {
+                        TreeNode<K,V> sp = s.parent;
+                        if ((p.parent = sp) != null) {
+                            if (s == sp.left)
+                                sp.left = p;
+                            else
+                                sp.right = p;
+                        }
+                        if ((s.right = pr) != null)
+                            pr.parent = s;
+                    }
+                    p.left = null;
+                    if ((p.right = sr) != null)
+                        sr.parent = p;
+                    if ((s.left = pl) != null)
+                        pl.parent = s;
+                    if ((s.parent = pp) == null)
+                        r = s;
+                    else if (p == pp.left)
+                        pp.left = s;
+                    else
+                        pp.right = s;
+                    if (sr != null)
+                        replacement = sr;
+                    else
+                        replacement = p;
+                }
+                else if (pl != null)
+                    replacement = pl;
+                else if (pr != null)
+                    replacement = pr;
+                else
+                    replacement = p;
+                if (replacement != p) {
+                    TreeNode<K,V> pp = replacement.parent = p.parent;
+                    if (pp == null)
+                        r = replacement;
+                    else if (p == pp.left)
+                        pp.left = replacement;
+                    else
+                        pp.right = replacement;
+                    p.left = p.right = p.parent = null;
+                }
+
+                root = (p.red) ? r : balanceDeletion(r, replacement);
+
+                if (p == replacement) {  // detach pointers
+                    TreeNode<K,V> pp;
+                    if ((pp = p.parent) != null) {
+                        if (p == pp.left)
+                            pp.left = null;
+                        else if (p == pp.right)
+                            pp.right = null;
+                        p.parent = null;
+                    }
+                }
+            } finally {
+                unlockRoot();
+            }
+            assert checkInvariants(root);
+            return false;
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;) {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks invariants recursively for the tree of Nodes rooted at t.
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+
+        private static final long LOCKSTATE
+            = U.objectFieldOffset(TreeBin.class, "lockState");
+    }
+
+    /* ----------------Table Traversal -------------- */
+
+    /**
+     * Records the table, its length, and current traversal index for a
+     * traverser that must process a region of a forwarded table before
+     * proceeding with current table.
+     */
+    static final class TableStack<K,V> {
+        int length;
+        int index;
+        Node<K,V>[] tab;
+        TableStack<K,V> next;
+    }
+
+    /**
+     * Encapsulates traversal for methods such as containsValue; also
+     * serves as a base class for other iterators and spliterators.
+     *
+     * Method advance visits once each still-valid node that was
+     * reachable upon iterator construction. It might miss some that
+     * were added to a bin after the bin was visited, which is OK wrt
+     * consistency guarantees. Maintaining this property in the face
+     * of possible ongoing resizes requires a fair amount of
+     * bookkeeping state that is difficult to optimize away amidst
+     * volatile accesses.  Even so, traversal maintains reasonable
+     * throughput.
+     *
+     * Normally, iteration proceeds bin-by-bin traversing lists.
+     * However, if the table has been resized, then all future steps
+     * must traverse both the bin at the current index as well as at
+     * (index + baseSize); and so on for further resizings. To
+     * paranoically cope with potential sharing by users of iterators
+     * across threads, iteration terminates if a bounds checks fails
+     * for a table read.
+     */
+    static class Traverser<K,V> {
+        Node<K,V>[] tab;        // current table; updated if resized
+        Node<K,V> next;         // the next entry to use
+        TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
+        int index;              // index of bin to use next
+        int baseIndex;          // current index of initial table
+        int baseLimit;          // index bound for initial table
+        final int baseSize;     // initial table size
+
+        Traverser(Node<K,V>[] tab, int size, int index, int limit) {
+            this.tab = tab;
+            this.baseSize = size;
+            this.baseIndex = this.index = index;
+            this.baseLimit = limit;
+            this.next = null;
+        }
+
+        /**
+         * Advances if possible, returning next valid node, or null if none.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;  // must use locals in checks
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex; // visit upper slots if present
+            }
+        }
+
+        /**
+         * Saves traversal state upon encountering a forwarding node.
+         */
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;  // reuse if possible
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        /**
+         * Possibly pops traversal state.
+         *
+         * @param n length of current table
+         */
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /**
+     * Base of key, value, and entry Iterators. Adds fields to
+     * Traverser to support iterator.remove.
+     */
+    static class BaseIterator<K,V> extends Traverser<K,V> {
+        final ConcurrentHashMap<K,V> map;
+        Node<K,V> lastReturned;
+        BaseIterator(Node<K,V>[] tab, int size, int index, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            advance();
+        }
+
+        public final boolean hasNext() { return next != null; }
+        public final boolean hasMoreElements() { return next != null; }
+
+        public final void remove() {
+            Node<K,V> p;
+            if ((p = lastReturned) == null)
+                throw new IllegalStateException();
+            lastReturned = null;
+            map.replaceNode(p.key, null, null);
+        }
+    }
+
+    static final class KeyIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<K>, Enumeration<K> {
+        KeyIterator(Node<K,V>[] tab, int size, int index, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit, map);
+        }
+
+        public final K next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            lastReturned = p;
+            advance();
+            return k;
+        }
+
+        public final K nextElement() { return next(); }
+    }
+
+    static final class ValueIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<V>, Enumeration<V> {
+        ValueIterator(Node<K,V>[] tab, int size, int index, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit, map);
+        }
+
+        public final V next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return v;
+        }
+
+        public final V nextElement() { return next(); }
+    }
+
+    static final class EntryIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<Map.Entry<K,V>> {
+        EntryIterator(Node<K,V>[] tab, int size, int index, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit, map);
+        }
+
+        public final Map.Entry<K,V> next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return new MapEntry<K,V>(k, v, map);
+        }
+    }
+
+    /**
+     * Exported Entry for EntryIterator.
+     */
+    static final class MapEntry<K,V> implements Map.Entry<K,V> {
+        final K key; // non-null
+        V val;       // non-null
+        final ConcurrentHashMap<K,V> map;
+        MapEntry(K key, V val, ConcurrentHashMap<K,V> map) {
+            this.key = key;
+            this.val = val;
+            this.map = map;
+        }
+        public K getKey()        { return key; }
+        public V getValue()      { return val; }
+        public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
+        public String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+
+        public boolean equals(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == val || v.equals(val)));
+        }
+
+        /**
+         * Sets our entry's value and writes through to the map. The
+         * value to return is somewhat arbitrary here. Since we do not
+         * necessarily track asynchronous changes, the most recent
+         * "previous" value could be different from what we return (or
+         * could even have been removed, in which case the put will
+         * re-establish). We do not and cannot guarantee more.
+         */
+        public V setValue(V value) {
+            if (value == null) throw new NullPointerException();
+            V v = val;
+            val = value;
+            map.put(key, value);
+            return v;
+        }
+    }
+
+    static final class KeySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<K> {
+        long est;               // size estimate
+        KeySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                       long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                        f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.key);
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.key);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    static final class ValueSpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<V> {
+        long est;               // size estimate
+        ValueSpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.val);
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.val);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.NONNULL;
+        }
+    }
+
+    static final class EntrySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        final ConcurrentHashMap<K,V> map; // To export MapEntry
+        long est;               // size estimate
+        EntrySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est, ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            this.est = est;
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1, map);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null; )
+                action.accept(new MapEntry<K,V>(p.key, p.val, map));
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Parallel bulk operations
+
+    /**
+     * Computes initial batch value for bulk tasks. The returned value
+     * is approximately exp2 of the number of times (minus one) to
+     * split task by two before executing leaf action. This value is
+     * faster to compute and more convenient to use as a guide to
+     * splitting than is the depth, since it is used while dividing by
+     * two anyway.
+     */
+    final int batchFor(long b) {
+        long n;
+        if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
+            return 0;
+        int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
+        return (b <= 0L || (n /= b) >= sp) ? sp : (int)n;
+    }
+
+    /**
+     * Performs the given action for each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEach(long parallelismThreshold,
+                        BiConsumer<? super K,? super V> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachMappingTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEach(long parallelismThreshold,
+                            BiFunction<? super K, ? super V, ? extends U> transformer,
+                            Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedMappingTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each (key, value), or null if none.  Upon
+     * success, further element processing is suppressed and the
+     * results of any other parallel invocations of the search
+     * function are ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each (key, value), or null if none
+     * @since 1.8
+     */
+    public <U> U search(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public <U> U reduce(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> transformer,
+                        BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public double reduceToDouble(long parallelismThreshold,
+                                 ToDoubleBiFunction<? super K, ? super V> transformer,
+                                 double basis,
+                                 DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public long reduceToLong(long parallelismThreshold,
+                             ToLongBiFunction<? super K, ? super V> transformer,
+                             long basis,
+                             LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public int reduceToInt(long parallelismThreshold,
+                           ToIntBiFunction<? super K, ? super V> transformer,
+                           int basis,
+                           IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachKey(long parallelismThreshold,
+                           Consumer<? super K> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachKeyTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachKey(long parallelismThreshold,
+                               Function<? super K, ? extends U> transformer,
+                               Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedKeyTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each key, or null if none. Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each key, or null if none
+     * @since 1.8
+     */
+    public <U> U searchKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all keys using the given
+     * reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all keys using the given
+     * reducer to combine values, or null if none
+     * @since 1.8
+     */
+    public K reduceKeys(long parallelismThreshold,
+                        BiFunction<? super K, ? super K, ? extends K> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceKeysTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public <U> U reduceKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> transformer,
+         BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public double reduceKeysToDouble(long parallelismThreshold,
+                                     ToDoubleFunction<? super K> transformer,
+                                     double basis,
+                                     DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public long reduceKeysToLong(long parallelismThreshold,
+                                 ToLongFunction<? super K> transformer,
+                                 long basis,
+                                 LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public int reduceKeysToInt(long parallelismThreshold,
+                               ToIntFunction<? super K> transformer,
+                               int basis,
+                               IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachValue(long parallelismThreshold,
+                             Consumer<? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        new ForEachValueTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachValue(long parallelismThreshold,
+                                 Function<? super V, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedValueTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each value, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each value, or null if none
+     * @since 1.8
+     */
+    public <U> U searchValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all values using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all values
+     * @since 1.8
+     */
+    public V reduceValues(long parallelismThreshold,
+                          BiFunction<? super V, ? super V, ? extends V> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceValuesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public <U> U reduceValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> transformer,
+                              BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public double reduceValuesToDouble(long parallelismThreshold,
+                                       ToDoubleFunction<? super V> transformer,
+                                       double basis,
+                                       DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public long reduceValuesToLong(long parallelismThreshold,
+                                   ToLongFunction<? super V> transformer,
+                                   long basis,
+                                   LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public int reduceValuesToInt(long parallelismThreshold,
+                                 ToIntFunction<? super V> transformer,
+                                 int basis,
+                                 IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachEntry(long parallelismThreshold,
+                             Consumer<? super Map.Entry<K,V>> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachEntryTask<K,V>(null, batchFor(parallelismThreshold), 0, 0, table,
+                                  action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachEntry(long parallelismThreshold,
+                                 Function<Map.Entry<K,V>, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedEntryTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each entry, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each entry, or null if none
+     * @since 1.8
+     */
+    public <U> U searchEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all entries using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all entries
+     * @since 1.8
+     */
+    public Map.Entry<K,V> reduceEntries(long parallelismThreshold,
+                                        BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceEntriesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public <U> U reduceEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> transformer,
+                               BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public double reduceEntriesToDouble(long parallelismThreshold,
+                                        ToDoubleFunction<Map.Entry<K,V>> transformer,
+                                        double basis,
+                                        DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public long reduceEntriesToLong(long parallelismThreshold,
+                                    ToLongFunction<Map.Entry<K,V>> transformer,
+                                    long basis,
+                                    LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public int reduceEntriesToInt(long parallelismThreshold,
+                                  ToIntFunction<Map.Entry<K,V>> transformer,
+                                  int basis,
+                                  IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+
+    /* ----------------Views -------------- */
+
+    /**
+     * Base class for views.
+     */
+    abstract static class CollectionView<K,V,E>
+        implements Collection<E>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        final ConcurrentHashMap<K,V> map;
+        CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }
+
+        /**
+         * Returns the map backing this view.
+         *
+         * @return the map backing this view
+         */
+        public ConcurrentHashMap<K,V> getMap() { return map; }
+
+        /**
+         * Removes all of the elements from this view, by removing all
+         * the mappings from the map backing this view.
+         */
+        public final void clear()      { map.clear(); }
+        public final int size()        { return map.size(); }
+        public final boolean isEmpty() { return map.isEmpty(); }
+
+        // implementations below rely on concrete classes supplying these
+        // abstract methods
+        /**
+         * Returns an iterator over the elements in this collection.
+         *
+         * <p>The returned iterator is
+         * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+         *
+         * @return an iterator over the elements in this collection
+         */
+        public abstract Iterator<E> iterator();
+        public abstract boolean contains(Object o);
+        public abstract boolean remove(Object o);
+
+        private static final String OOME_MSG = "Required array size too large";
+
+        public final Object[] toArray() {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int n = (int)sz;
+            Object[] r = new Object[n];
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = e;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final <T> T[] toArray(T[] a) {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int m = (int)sz;
+            T[] r = (a.length >= m) ? a :
+                (T[])java.lang.reflect.Array
+                .newInstance(a.getClass().getComponentType(), m);
+            int n = r.length;
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = (T)e;
+            }
+            if (a == r && i < n) {
+                r[i] = null; // null-terminate
+                return r;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        /**
+         * Returns a string representation of this collection.
+         * The string representation consists of the string representations
+         * of the collection's elements in the order they are returned by
+         * its iterator, enclosed in square brackets ({@code "[]"}).
+         * Adjacent elements are separated by the characters {@code ", "}
+         * (comma and space).  Elements are converted to strings as by
+         * {@link String#valueOf(Object)}.
+         *
+         * @return a string representation of this collection
+         */
+        public final String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            Iterator<E> it = iterator();
+            if (it.hasNext()) {
+                for (;;) {
+                    Object e = it.next();
+                    sb.append(e == this ? "(this Collection)" : e);
+                    if (!it.hasNext())
+                        break;
+                    sb.append(',').append(' ');
+                }
+            }
+            return sb.append(']').toString();
+        }
+
+        public final boolean containsAll(Collection<?> c) {
+            if (c != this) {
+                for (Object e : c) {
+                    if (e == null || !contains(e))
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            // Use (c instanceof Set) as a hint that lookup in c is as
+            // efficient as this view
+            Node<K,V>[] t;
+            if ((t = map.table) == null) {
+                return false;
+            } else if (c instanceof Set<?> && c.size() > t.length) {
+                for (Iterator<?> it = iterator(); it.hasNext(); ) {
+                    if (c.contains(it.next())) {
+                        it.remove();
+                        modified = true;
+                    }
+                }
+            } else {
+                for (Object e : c)
+                    modified |= remove(e);
+            }
+            return modified;
+        }
+
+        public final boolean retainAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (!c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of keys, in
+     * which additions may optionally be enabled by mapping to a
+     * common value.  This class cannot be directly instantiated.
+     * See {@link #keySet(Object) keySet(V)},
+     * {@link #newKeySet() newKeySet()},
+     * {@link #newKeySet(int) newKeySet(int)}.
+     *
+     * @since 1.8
+     */
+    public static class KeySetView<K,V> extends CollectionView<K,V,K>
+        implements Set<K>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final V value;
+        KeySetView(ConcurrentHashMap<K,V> map, V value) {  // non-public
+            super(map);
+            this.value = value;
+        }
+
+        /**
+         * Returns the default mapped value for additions,
+         * or {@code null} if additions are not supported.
+         *
+         * @return the default mapped value for additions, or {@code null}
+         * if not supported
+         */
+        public V getMappedValue() { return value; }
+
+        /**
+         * {@inheritDoc}
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean contains(Object o) { return map.containsKey(o); }
+
+        /**
+         * Removes the key from this map view, by removing the key (and its
+         * corresponding value) from the backing map.  This method does
+         * nothing if the key is not in the map.
+         *
+         * @param  o the key to be removed from the backing map
+         * @return {@code true} if the backing map contained the specified key
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean remove(Object o) { return map.remove(o) != null; }
+
+        /**
+         * @return an iterator over the keys of the backing map
+         */
+        public Iterator<K> iterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeyIterator<K,V>(t, f, 0, f, m);
+        }
+
+        /**
+         * Adds the specified key to this set view by mapping the key to
+         * the default mapped value in the backing map, if defined.
+         *
+         * @param e key to be added
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the specified key is null
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean add(K e) {
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            return map.putVal(e, v, true) == null;
+        }
+
+        /**
+         * Adds all of the elements in the specified collection to this set,
+         * as if by calling {@link #add} on each one.
+         *
+         * @param c the elements to be inserted into this set
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the collection or any of its
+         * elements are {@code null}
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean addAll(Collection<? extends K> c) {
+            boolean added = false;
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            for (K e : c) {
+                if (map.putVal(e, v, true) == null)
+                    added = true;
+            }
+            return added;
+        }
+
+        public int hashCode() {
+            int h = 0;
+            for (K e : this)
+                h += e.hashCode();
+            return h;
+        }
+
+        public boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<K> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.key);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Collection} of
+     * values, in which additions are disabled. This class cannot be
+     * directly instantiated. See {@link #values()}.
+     */
+    static final class ValuesView<K,V> extends CollectionView<K,V,V>
+        implements Collection<V>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        ValuesView(ConcurrentHashMap<K,V> map) { super(map); }
+        public final boolean contains(Object o) {
+            return map.containsValue(o);
+        }
+
+        public final boolean remove(Object o) {
+            if (o != null) {
+                for (Iterator<V> it = iterator(); it.hasNext();) {
+                    if (o.equals(it.next())) {
+                        it.remove();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public final Iterator<V> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public final boolean add(V e) {
+            throw new UnsupportedOperationException();
+        }
+        public final boolean addAll(Collection<? extends V> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<V> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            return map.removeValueIf(filter);
+        }
+
+        public Spliterator<V> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueSpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.val);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of (key, value)
+     * entries.  This class cannot be directly instantiated. See
+     * {@link #entrySet()}.
+     */
+    static final class EntrySetView<K,V> extends CollectionView<K,V,Map.Entry<K,V>>
+        implements Set<Map.Entry<K,V>>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        EntrySetView(ConcurrentHashMap<K,V> map) { super(map); }
+
+        public boolean contains(Object o) {
+            Object k, v, r; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (r = map.get(k)) != null &&
+                    (v = e.getValue()) != null &&
+                    (v == r || v.equals(r)));
+        }
+
+        public boolean remove(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    map.remove(k, v));
+        }
+
+        /**
+         * @return an iterator over the entries of the backing map
+         */
+        public Iterator<Map.Entry<K,V>> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntryIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public boolean add(Entry<K,V> e) {
+            return map.putVal(e.getKey(), e.getValue(), false) == null;
+        }
+
+        public boolean addAll(Collection<? extends Entry<K,V>> c) {
+            boolean added = false;
+            for (Entry<K,V> e : c) {
+                if (add(e))
+                    added = true;
+            }
+            return added;
+        }
+
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            return map.removeEntryIf(filter);
+        }
+
+        public final int hashCode() {
+            int h = 0;
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; ) {
+                    h += p.hashCode();
+                }
+            }
+            return h;
+        }
+
+        public final boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntrySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n, m);
+        }
+
+        public void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------
+
+    /**
+     * Base class for bulk tasks. Repeats some fields and code from
+     * class Traverser, because we need to subclass CountedCompleter.
+     */
+    @SuppressWarnings("serial")
+    abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
+        Node<K,V>[] tab;        // same as Traverser
+        Node<K,V> next;
+        TableStack<K,V> stack, spare;
+        int index;
+        int baseIndex;
+        int baseLimit;
+        final int baseSize;
+        int batch;              // split control
+
+        BulkTask(BulkTask<K,V,?> par, int b, int i, int f, Node<K,V>[] t) {
+            super(par);
+            this.batch = b;
+            this.index = this.baseIndex = i;
+            if ((this.tab = t) == null)
+                this.baseSize = this.baseLimit = 0;
+            else if (par == null)
+                this.baseSize = this.baseLimit = t.length;
+            else {
+                this.baseLimit = f;
+                this.baseSize = par.baseSize;
+            }
+        }
+
+        /**
+         * Same as Traverser version.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex;
+            }
+        }
+
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /*
+     * Task classes. Coded in a regular but ugly format/style to
+     * simplify checks that each variant differs in the right way from
+     * others. The null screenings exist because compilers cannot tell
+     * that we've already null-checked task arguments, so we force
+     * simplest hoisted bypass to help avoid convoluted traps.
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachKeyTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super K> action;
+        ForEachKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super K> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super K> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachKeyTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.key);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachValueTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super V> action;
+        ForEachValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachValueTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachEntryTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super Entry<K,V>> action;
+        ForEachEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super Entry<K,V>> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super Entry<K,V>> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachEntryTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachMappingTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final BiConsumer<? super K, ? super V> action;
+        ForEachMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiConsumer<? super K,? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final BiConsumer<? super K, ? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachMappingTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p.key, p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedKeyTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super K, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedKeyTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedValueTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedValueTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedEntryTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Map.Entry<K,V>, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedEntryTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedMappingTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedMappingTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super K, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchKeysTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchValuesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Entry<K,V>, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Entry<K,V>, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<Entry<K,V>, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchEntriesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchMappingsTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key, p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceKeysTask<K,V>
+        extends BulkTask<K,V,K> {
+        final BiFunction<? super K, ? super K, ? extends K> reducer;
+        K result;
+        ReduceKeysTask<K,V> rights, nextRight;
+        ReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceKeysTask<K,V> nextRight,
+             BiFunction<? super K, ? super K, ? extends K> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final K getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super K, ? extends K> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceKeysTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                K r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    K u = p.key;
+                    r = (r == null) ? u : u == null ? r : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceKeysTask<K,V>
+                        t = (ReduceKeysTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        K tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceValuesTask<K,V>
+        extends BulkTask<K,V,V> {
+        final BiFunction<? super V, ? super V, ? extends V> reducer;
+        V result;
+        ReduceValuesTask<K,V> rights, nextRight;
+        ReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceValuesTask<K,V> nextRight,
+             BiFunction<? super V, ? super V, ? extends V> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final V getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super V, ? super V, ? extends V> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceValuesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                V r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    V v = p.val;
+                    r = (r == null) ? v : reducer.apply(r, v);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceValuesTask<K,V>
+                        t = (ReduceValuesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        V tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceEntriesTask<K,V>
+        extends BulkTask<K,V,Map.Entry<K,V>> {
+        final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+        Map.Entry<K,V> result;
+        ReduceEntriesTask<K,V> rights, nextRight;
+        ReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceEntriesTask<K,V> nextRight,
+             BiFunction<Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final Map.Entry<K,V> getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceEntriesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                Map.Entry<K,V> r = null;
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = (r == null) ? p : reducer.apply(r, p);
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceEntriesTask<K,V>
+                        t = (ReduceEntriesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        Map.Entry<K,V> tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceKeysTask<K,V,U> rights, nextRight;
+        MapReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysTask<K,V,U> nextRight,
+             Function<? super K, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysTask<K,V,U>
+                        t = (MapReduceKeysTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceValuesTask<K,V,U> rights, nextRight;
+        MapReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesTask<K,V,U> nextRight,
+             Function<? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesTask<K,V,U>
+                        t = (MapReduceValuesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceEntriesTask<K,V,U> rights, nextRight;
+        MapReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesTask<K,V,U> nextRight,
+             Function<Map.Entry<K,V>, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesTask<K,V,U>
+                        t = (MapReduceEntriesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceMappingsTask<K,V,U> rights, nextRight;
+        MapReduceMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsTask<K,V,U> nextRight,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsTask<K,V,U>
+                        t = (MapReduceMappingsTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super K> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceKeysToDoubleTask<K,V> rights, nextRight;
+        MapReduceKeysToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super K> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super K> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToDoubleTask<K,V>
+                        t = (MapReduceKeysToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceValuesToDoubleTask<K,V> rights, nextRight;
+        MapReduceValuesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToDoubleTask<K,V>
+                        t = (MapReduceValuesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<Map.Entry<K,V>> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceEntriesToDoubleTask<K,V> rights, nextRight;
+        MapReduceEntriesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<Map.Entry<K,V>> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<Map.Entry<K,V>> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToDoubleTask<K,V>
+                        t = (MapReduceEntriesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleBiFunction<? super K, ? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceMappingsToDoubleTask<K,V> rights, nextRight;
+        MapReduceMappingsToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToDoubleTask<K,V> nextRight,
+             ToDoubleBiFunction<? super K, ? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleBiFunction<? super K, ? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToDoubleTask<K,V>
+                        t = (MapReduceMappingsToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super K> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceKeysToLongTask<K,V> rights, nextRight;
+        MapReduceKeysToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToLongTask<K,V> nextRight,
+             ToLongFunction<? super K> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super K> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToLongTask<K,V>
+                        t = (MapReduceKeysToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceValuesToLongTask<K,V> rights, nextRight;
+        MapReduceValuesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToLongTask<K,V> nextRight,
+             ToLongFunction<? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToLongTask<K,V>
+                        t = (MapReduceValuesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<Map.Entry<K,V>> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceEntriesToLongTask<K,V> rights, nextRight;
+        MapReduceEntriesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToLongTask<K,V> nextRight,
+             ToLongFunction<Map.Entry<K,V>> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<Map.Entry<K,V>> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToLongTask<K,V>
+                        t = (MapReduceEntriesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongBiFunction<? super K, ? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceMappingsToLongTask<K,V> rights, nextRight;
+        MapReduceMappingsToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToLongTask<K,V> nextRight,
+             ToLongBiFunction<? super K, ? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongBiFunction<? super K, ? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToLongTask<K,V>
+                        t = (MapReduceMappingsToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super K> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceKeysToIntTask<K,V> rights, nextRight;
+        MapReduceKeysToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToIntTask<K,V> nextRight,
+             ToIntFunction<? super K> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super K> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToIntTask<K,V>
+                        t = (MapReduceKeysToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceValuesToIntTask<K,V> rights, nextRight;
+        MapReduceValuesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToIntTask<K,V> nextRight,
+             ToIntFunction<? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToIntTask<K,V>
+                        t = (MapReduceValuesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<Map.Entry<K,V>> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceEntriesToIntTask<K,V> rights, nextRight;
+        MapReduceEntriesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToIntTask<K,V> nextRight,
+             ToIntFunction<Map.Entry<K,V>> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<Map.Entry<K,V>> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToIntTask<K,V>
+                        t = (MapReduceEntriesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntBiFunction<? super K, ? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceMappingsToIntTask<K,V> rights, nextRight;
+        MapReduceMappingsToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToIntTask<K,V> nextRight,
+             ToIntBiFunction<? super K, ? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntBiFunction<? super K, ? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToIntTask<K,V>
+                        t = (MapReduceMappingsToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long SIZECTL
+        = U.objectFieldOffset(ConcurrentHashMap.class, "sizeCtl");
+    private static final long TRANSFERINDEX
+        = U.objectFieldOffset(ConcurrentHashMap.class, "transferIndex");
+    private static final long BASECOUNT
+        = U.objectFieldOffset(ConcurrentHashMap.class, "baseCount");
+    private static final long CELLSBUSY
+        = U.objectFieldOffset(ConcurrentHashMap.class, "cellsBusy");
+    private static final long CELLVALUE
+        = U.objectFieldOffset(CounterCell.class, "value");
+    private static final int ABASE = U.arrayBaseOffset(Node[].class);
+    private static final int ASHIFT;
+
+    static {
+        int scale = U.arrayIndexScale(Node[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new ExceptionInInitializerError("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+
+        // Eager class load observed to help JIT during startup
+        ensureLoaded = ReservationNode.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/ConcurrentLinkedDeque.java b/android-35/java/util/concurrent/ConcurrentLinkedDeque.java
new file mode 100644
index 0000000..91ddabd
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -0,0 +1,1677 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea 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/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.AbstractCollection;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
+ * Concurrent insertion, removal, and access operations execute safely
+ * across multiple threads.
+ * A {@code ConcurrentLinkedDeque} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <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, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe 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.
+ *
+ * <p>Memory consistency effects: As with other concurrent collections,
+ * actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedDeque} in another thread.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @author Martin Buchholz
+ * @param <E> the type of elements held in this deque
+ */
+public class ConcurrentLinkedDeque<E>
+    extends AbstractCollection<E>
+    implements Deque<E>, java.io.Serializable {
+
+    /*
+     * This is an implementation of a concurrent lock-free deque
+     * supporting interior removes but not interior insertions, as
+     * required to support the entire Deque interface.
+     *
+     * We extend the techniques developed for ConcurrentLinkedQueue and
+     * LinkedTransferQueue (see the internal docs for those classes).
+     * Understanding the ConcurrentLinkedQueue implementation is a
+     * prerequisite for understanding the implementation of this class.
+     *
+     * The data structure is a symmetrical doubly-linked "GC-robust"
+     * linked list of nodes.  We minimize the number of volatile writes
+     * using two techniques: advancing multiple hops with a single CAS
+     * and mixing volatile and non-volatile writes of the same memory
+     * locations.
+     *
+     * A node contains the expected E ("item") and links to predecessor
+     * ("prev") and successor ("next") nodes:
+     *
+     * class Node<E> { volatile Node<E> prev, next; volatile E item; }
+     *
+     * A node p is considered "live" if it contains a non-null item
+     * (p.item != null).  When an item is CASed to null, the item is
+     * atomically logically deleted from the collection.
+     *
+     * At any time, there is precisely one "first" node with a null
+     * prev reference that terminates any chain of prev references
+     * starting at a live node.  Similarly there is precisely one
+     * "last" node terminating any chain of next references starting at
+     * a live node.  The "first" and "last" nodes may or may not be live.
+     * The "first" and "last" nodes are always mutually reachable.
+     *
+     * A new element is added atomically by CASing the null prev or
+     * next reference in the first or last node to a fresh node
+     * containing the element.  The element's node atomically becomes
+     * "live" at that point.
+     *
+     * A node is considered "active" if it is a live node, or the
+     * first or last node.  Active nodes cannot be unlinked.
+     *
+     * A "self-link" is a next or prev reference that is the same node:
+     *   p.prev == p  or  p.next == p
+     * Self-links are used in the node unlinking process.  Active nodes
+     * never have self-links.
+     *
+     * A node p is active if and only if:
+     *
+     * p.item != null ||
+     * (p.prev == null && p.next != p) ||
+     * (p.next == null && p.prev != p)
+     *
+     * The deque object has two node references, "head" and "tail".
+     * The head and tail are only approximations to the first and last
+     * nodes of the deque.  The first node can always be found by
+     * following prev pointers from head; likewise for tail.  However,
+     * it is permissible for head and tail to be referring to deleted
+     * nodes that have been unlinked and so may not be reachable from
+     * any live node.
+     *
+     * There are 3 stages of node deletion;
+     * "logical deletion", "unlinking", and "gc-unlinking".
+     *
+     * 1. "logical deletion" by CASing item to null atomically removes
+     * the element from the collection, and makes the containing node
+     * eligible for unlinking.
+     *
+     * 2. "unlinking" makes a deleted node unreachable from active
+     * nodes, and thus eventually reclaimable by GC.  Unlinked nodes
+     * may remain reachable indefinitely from an iterator.
+     *
+     * Physical node unlinking is merely an optimization (albeit a
+     * critical one), and so can be performed at our convenience.  At
+     * any time, the set of live nodes maintained by prev and next
+     * links are identical, that is, the live nodes found via next
+     * links from the first node is equal to the elements found via
+     * prev links from the last node.  However, this is not true for
+     * nodes that have already been logically deleted - such nodes may
+     * be reachable in one direction only.
+     *
+     * 3. "gc-unlinking" takes unlinking further by making active
+     * nodes unreachable from deleted nodes, making it easier for the
+     * GC to reclaim future deleted nodes.  This step makes the data
+     * structure "gc-robust", as first described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282).
+     *
+     * GC-unlinked nodes may remain reachable indefinitely from an
+     * iterator, but unlike unlinked nodes, are never reachable from
+     * head or tail.
+     *
+     * Making the data structure GC-robust will eliminate the risk of
+     * unbounded memory retention with conservative GCs and is likely
+     * to improve performance with generational GCs.
+     *
+     * When a node is dequeued at either end, e.g. via poll(), we would
+     * like to break any references from the node to active nodes.  We
+     * develop further the use of self-links that was very effective in
+     * other concurrent collection classes.  The idea is to replace
+     * prev and next pointers with special values that are interpreted
+     * to mean off-the-list-at-one-end.  These are approximations, but
+     * good enough to preserve the properties we want in our
+     * traversals, e.g. we guarantee that a traversal will never visit
+     * the same element twice, but we don't guarantee whether a
+     * traversal that runs out of elements will be able to see more
+     * elements later after enqueues at that end.  Doing gc-unlinking
+     * safely is particularly tricky, since any node can be in use
+     * indefinitely (for example by an iterator).  We must ensure that
+     * the nodes pointed at by head/tail never get gc-unlinked, since
+     * head/tail are needed to get "back on track" by other nodes that
+     * are gc-unlinked.  gc-unlinking accounts for much of the
+     * implementation complexity.
+     *
+     * Since neither unlinking nor gc-unlinking are necessary for
+     * correctness, there are many implementation choices regarding
+     * frequency (eagerness) of these operations.  Since volatile
+     * reads are likely to be much cheaper than CASes, saving CASes by
+     * unlinking multiple adjacent nodes at a time may be a win.
+     * gc-unlinking can be performed rarely and still be effective,
+     * since it is most important that long chains of deleted nodes
+     * are occasionally broken.
+     *
+     * The actual representation we use is that p.next == p means to
+     * goto the first node (which in turn is reached by following prev
+     * pointers from head), and p.next == null && p.prev == p means
+     * that the iteration is at an end and that p is a (static final)
+     * dummy node, NEXT_TERMINATOR, and not the last active node.
+     * Finishing the iteration when encountering such a TERMINATOR is
+     * good enough for read-only traversals, so such traversals can use
+     * p.next == null as the termination condition.  When we need to
+     * find the last (active) node, for enqueueing a new node, we need
+     * to check whether we have reached a TERMINATOR node; if so,
+     * restart traversal from tail.
+     *
+     * The implementation is completely directionally symmetrical,
+     * except that most public methods that iterate through the list
+     * follow next pointers, in the "forward" direction.
+     *
+     * We believe (without full proof) that all single-element Deque
+     * operations that operate directly at the two ends of the Deque
+     * (e.g., addFirst, peekLast, pollLast) are linearizable (see
+     * Herlihy and Shavit's book).  However, some combinations of
+     * operations are known not to be linearizable.  In particular,
+     * when an addFirst(A) is racing with pollFirst() removing B, it
+     * is possible for an observer iterating over the elements to
+     * observe first [A B C] and then [A C], even though no interior
+     * removes are ever performed.  Nevertheless, iterators behave
+     * reasonably, providing the "weakly consistent" guarantees.
+     *
+     * Empirically, microbenchmarks suggest that this class adds about
+     * 40% overhead relative to ConcurrentLinkedQueue, which feels as
+     * good as we can hope for.
+     */
+
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * A node from which the first node on list (that is, the unique node p
+     * with p.prev == null && p.next != p) can be reached in O(1) time.
+     * Invariants:
+     * - the first node is always O(1) reachable from head via prev links
+     * - all live nodes are reachable from the first node via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * - head is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - head.item may or may not be null
+     * - head may not be reachable from the first or last node, or from tail
+     */
+    private transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique node p
+     * with p.next == null && p.prev != p) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always O(1) reachable from tail via next links
+     * - all live nodes are reachable from the last node via pred()
+     * - tail != null
+     * - tail is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - tail.item may or may not be null
+     * - tail may not be reachable from the first or last node, or from head
+     */
+    private transient volatile Node<E> tail;
+
+    private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
+
+    @SuppressWarnings("unchecked")
+    Node<E> prevTerminator() {
+        return (Node<E>) PREV_TERMINATOR;
+    }
+
+    @SuppressWarnings("unchecked")
+    Node<E> nextTerminator() {
+        return (Node<E>) NEXT_TERMINATOR;
+    }
+
+    static final class Node<E> {
+        volatile Node<E> prev;
+        volatile E item;
+        volatile Node<E> next;
+    }
+
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via CAS.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        ITEM.set(node, item);
+        return node;
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p.next == p) // PREV_TERMINATOR
+                    continue restartFromHead;
+                else {
+                    // p is first node
+                    NEXT.set(newNode, p); // CAS piggyback
+                    if (PREV.compareAndSet(p, null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != h) // hop two nodes at a time; failure is OK
+                            HEAD.weakCompareAndSet(this, h, newNode);
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read prev
+                }
+            }
+    }
+
+    /**
+     * Links e as last element.
+     */
+    private void linkLast(E e) {
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    PREV.set(newNode, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != t) // hop two nodes at a time; failure is OK
+                            TAIL.weakCompareAndSet(this, t, newNode);
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    private static final int HOPS = 2;
+
+    /**
+     * Unlinks non-null node x.
+     */
+    void unlink(Node<E> x) {
+        // assert x != null;
+        // assert x.item == null;
+        // assert x != PREV_TERMINATOR;
+        // assert x != NEXT_TERMINATOR;
+
+        final Node<E> prev = x.prev;
+        final Node<E> next = x.next;
+        if (prev == null) {
+            unlinkFirst(x, next);
+        } else if (next == null) {
+            unlinkLast(x, prev);
+        } else {
+            // Unlink interior node.
+            //
+            // This is the common case, since a series of polls at the
+            // same end will be "interior" removes, except perhaps for
+            // the first one, since end nodes cannot be unlinked.
+            //
+            // At any time, all active nodes are mutually reachable by
+            // following a sequence of either next or prev pointers.
+            //
+            // Our strategy is to find the unique active predecessor
+            // and successor of x.  Try to fix up their links so that
+            // they point to each other, leaving x unreachable from
+            // active nodes.  If successful, and if x has no live
+            // predecessor/successor, we additionally try to gc-unlink,
+            // leaving active nodes unreachable from x, by rechecking
+            // that the status of predecessor and successor are
+            // unchanged and ensuring that x is not reachable from
+            // tail/head, before setting x's prev/next links to their
+            // logical approximate replacements, self/TERMINATOR.
+            Node<E> activePred, activeSucc;
+            boolean isFirst, isLast;
+            int hops = 1;
+
+            // Find active predecessor
+            for (Node<E> p = prev; ; ++hops) {
+                if (p.item != null) {
+                    activePred = p;
+                    isFirst = false;
+                    break;
+                }
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        return;
+                    activePred = p;
+                    isFirst = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // Find active successor
+            for (Node<E> p = next; ; ++hops) {
+                if (p.item != null) {
+                    activeSucc = p;
+                    isLast = false;
+                    break;
+                }
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        return;
+                    activeSucc = p;
+                    isLast = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // TODO: better HOP heuristics
+            if (hops < HOPS
+                // always squeeze out interior deleted nodes
+                && (isFirst | isLast))
+                return;
+
+            // Squeeze out deleted nodes between activePred and
+            // activeSucc, including x.
+            skipDeletedSuccessors(activePred);
+            skipDeletedPredecessors(activeSucc);
+
+            // Try to gc-unlink, if possible
+            if ((isFirst | isLast) &&
+
+                // Recheck expected state of predecessor and successor
+                (activePred.next == activeSucc) &&
+                (activeSucc.prev == activePred) &&
+                (isFirst ? activePred.prev == null : activePred.item != null) &&
+                (isLast  ? activeSucc.next == null : activeSucc.item != null)) {
+
+                updateHead(); // Ensure x is not reachable from head
+                updateTail(); // Ensure x is not reachable from tail
+
+                // Finally, actually gc-unlink
+                PREV.setRelease(x, isFirst ? prevTerminator() : x);
+                NEXT.setRelease(x, isLast  ? nextTerminator() : x);
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null first node.
+     */
+    private void unlinkFirst(Node<E> first, Node<E> next) {
+        // assert first != null;
+        // assert next != null;
+        // assert first.item == null;
+        for (Node<E> o = null, p = next, q;;) {
+            if (p.item != null || (q = p.next) == null) {
+                if (o != null && p.prev != p &&
+                    NEXT.compareAndSet(first, next, p)) {
+                    skipDeletedPredecessors(p);
+                    if (first.prev == null &&
+                        (p.next == null || p.item != null) &&
+                        p.prev == first) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        NEXT.setRelease(o, o);
+                        PREV.setRelease(o, prevTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null last node.
+     */
+    private void unlinkLast(Node<E> last, Node<E> prev) {
+        // assert last != null;
+        // assert prev != null;
+        // assert last.item == null;
+        for (Node<E> o = null, p = prev, q;;) {
+            if (p.item != null || (q = p.prev) == null) {
+                if (o != null && p.next != p &&
+                    PREV.compareAndSet(last, prev, p)) {
+                    skipDeletedSuccessors(p);
+                    if (last.next == null &&
+                        (p.prev == null || p.item != null) &&
+                        p.next == last) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        PREV.setRelease(o, o);
+                        NEXT.setRelease(o, nextTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from head after it returns.
+     * Does not guarantee to eliminate slack, only that head will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateHead() {
+        // Either head already points to an active node, or we keep
+        // trying to cas it to the first node until it does.
+        Node<E> h, p, q;
+        restartFromHead:
+        while ((h = head).item == null && (p = h.prev) != null) {
+            for (;;) {
+                if ((q = p.prev) == null ||
+                    (q = (p = q).prev) == null) {
+                    // It is possible that p is PREV_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (HEAD.compareAndSet(this, h, p))
+                        return;
+                    else
+                        continue restartFromHead;
+                }
+                else if (h != head)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from tail after it returns.
+     * Does not guarantee to eliminate slack, only that tail will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateTail() {
+        // Either tail already points to an active node, or we keep
+        // trying to cas it to the last node until it does.
+        Node<E> t, p, q;
+        restartFromTail:
+        while ((t = tail).item == null && (p = t.next) != null) {
+            for (;;) {
+                if ((q = p.next) == null ||
+                    (q = (p = q).next) == null) {
+                    // It is possible that p is NEXT_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (TAIL.compareAndSet(this, t, p))
+                        return;
+                    else
+                        continue restartFromTail;
+                }
+                else if (t != tail)
+                    continue restartFromTail;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    private void skipDeletedPredecessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> prev = x.prev;
+            // assert prev != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = prev;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (prev == p || PREV.compareAndSet(x, prev, p))
+                return;
+
+        } while (x.item != null || x.next == null);
+    }
+
+    private void skipDeletedSuccessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> next = x.next;
+            // assert next != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = next;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (next == p || NEXT.compareAndSet(x, next, p))
+                return;
+
+        } while (x.item != null || x.prev == null);
+    }
+
+    /**
+     * Returns the successor of p, or the first 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<E> succ(Node<E> p) {
+        // TODO: should we skip deleted nodes here?
+        if (p == (p = p.next))
+            p = first();
+        return p;
+    }
+
+    /**
+     * Returns the predecessor of p, or the last node if p.prev has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> pred(Node<E> p) {
+        if (p == (p = p.prev))
+            p = last();
+        return p;
+    }
+
+    /**
+     * Returns the first node, the unique node p for which:
+     *     p.prev == null && p.next != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that head is set to the returned node.
+     */
+    Node<E> first() {
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p == h
+                         // It is possible that p is PREV_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || HEAD.compareAndSet(this, h, p))
+                    return p;
+                else
+                    continue restartFromHead;
+            }
+    }
+
+    /**
+     * Returns the last node, the unique node p for which:
+     *     p.next == null && p.prev != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that tail is set to the returned node.
+     */
+    Node<E> last() {
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p == t
+                         // It is possible that p is NEXT_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || TAIL.compareAndSet(this, t, p))
+                    return p;
+                else
+                    continue restartFromTail;
+            }
+    }
+
+    // Minor convenience utilities
+
+    /**
+     * Returns element unless it is null, in which case throws
+     * NoSuchElementException.
+     *
+     * @param v the element
+     * @return the element
+     */
+    private E screenNullResult(E v) {
+        if (v == null)
+            throw new NoSuchElementException();
+        return v;
+    }
+
+    /**
+     * Constructs an empty deque.
+     */
+    public ConcurrentLinkedDeque() {
+        head = tail = new Node<E>();
+    }
+
+    /**
+     * Constructs a deque 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 ConcurrentLinkedDeque(Collection<? extends E> c) {
+        // Copy c into a private chain of Nodes
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else {
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    /**
+     * Initializes head and tail, ensuring invariants hold.
+     */
+    private void initHeadTail(Node<E> h, Node<E> t) {
+        if (h == t) {
+            if (h == null)
+                h = t = new Node<E>();
+            else {
+                // Avoid edge case of a single Node with non-null item.
+                Node<E> newNode = new Node<E>();
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
+                t = newNode;
+            }
+        }
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        linkFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    public E peekFirst() {
+        restart: for (;;) {
+            E item;
+            Node<E> first = first(), p = first;
+            while ((item = p.item) == null) {
+                if (p == (p = p.next)) continue restart;
+                if (p == null)
+                    break;
+            }
+            // recheck for linearizability
+            if (first.prev != null) continue restart;
+            return item;
+        }
+    }
+
+    public E peekLast() {
+        restart: for (;;) {
+            E item;
+            Node<E> last = last(), p = last;
+            while ((item = p.item) == null) {
+                if (p == (p = p.prev)) continue restart;
+                if (p == null)
+                    break;
+            }
+            // recheck for linearizability
+            if (last.next != null) continue restart;
+            return item;
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        return screenNullResult(peekFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        return screenNullResult(peekLast());
+    }
+
+    public E pollFirst() {
+        restart: for (;;) {
+            for (Node<E> first = first(), p = first;;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    // recheck for linearizability
+                    if (first.prev != null) continue restart;
+                    if (ITEM.compareAndSet(p, item, null)) {
+                        unlink(p);
+                        return item;
+                    }
+                }
+                if (p == (p = p.next)) continue restart;
+                if (p == null) {
+                    if (first.prev != null) continue restart;
+                    return null;
+                }
+            }
+        }
+    }
+
+    public E pollLast() {
+        restart: for (;;) {
+            for (Node<E> last = last(), p = last;;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    // recheck for linearizability
+                    if (last.next != null) continue restart;
+                    if (ITEM.compareAndSet(p, item, null)) {
+                        unlink(p);
+                        return item;
+                    }
+                }
+                if (p == (p = p.prev)) continue restart;
+                if (p == null) {
+                    if (last.next != null) continue restart;
+                    return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        return screenNullResult(pollFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        return screenNullResult(pollLast());
+    }
+
+    // *** Queue and stack methods ***
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque 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) {
+        return offerLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque 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) {
+        return offerLast(e);
+    }
+
+    public E poll()           { return pollFirst(); }
+    public E peek()           { return peekFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove()         { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop()            { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element()        { return getFirst(); }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e)     { addFirst(e); }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            final E item;
+            if ((item = p.item) != null
+                && o.equals(item)
+                && ITEM.compareAndSet(p, item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeLastOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            final E item;
+            if ((item = p.item) != null
+                && o.equals(item)
+                && ITEM.compareAndSet(p, item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                final E item;
+                if ((item = p.item) != null && o.equals(item))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this collection contains no elements.
+     *
+     * @return {@code true} if this collection contains no elements
+     */
+    public boolean isEmpty() {
+        return peekFirst() == null;
+    }
+
+    /**
+     * Returns the number of elements in this deque.  If this deque
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * 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 deques, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        restart: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restart;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this deque, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a deque to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this deque
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else {
+                NEXT.set(last, newNode);
+                PREV.set(newNode, last);
+                last = newNode;
+            }
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    PREV.set(beginningOfTheEnd, p); // CAS piggyback
+                    if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
+                        // Successful CAS is the linearization point
+                        // for all elements to be added to this deque.
+                        if (!TAIL.weakCompareAndSet(this, t, last)) {
+                            // Try a little harder to update tail,
+                            // since we may be adding many elements.
+                            t = tail;
+                            if (last.next == null)
+                                TAIL.weakCompareAndSet(this, t, last);
+                        }
+                        return true;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     */
+    public void clear() {
+        while (pollFirst() != null)
+            ;
+    }
+
+    public String toString() {
+        String[] a = null;
+        restart: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restart;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restart: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restart;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque,
+     * in proper sequence (from first to last element); the runtime
+     * type of the returned array is that of the specified array.  If
+     * the deque fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of
+     * the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as
+     * bridge between array-based and collection-based APIs.  Further,
+     * this method allows precise control over the runtime type of the
+     * output array, and may, under certain circumstances, be used to
+     * save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> startNode();
+        abstract Node<E> nextNode(Node<E> p);
+
+        AbstractItr() {
+            advance();
+        }
+
+        /**
+         * Sets nextNode and nextItem to next valid node, or to null
+         * if no such.
+         */
+        private void advance() {
+            lastRet = nextNode;
+
+            Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
+            for (;; p = nextNode(p)) {
+                if (p == null) {
+                    // might be at active end or TERMINATOR node; both are OK
+                    nextNode = null;
+                    nextItem = null;
+                    break;
+                }
+                final E item;
+                if ((item = p.item) != null) {
+                    nextNode = p;
+                    nextItem = item;
+                    break;
+                }
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            E item = nextItem;
+            if (item == null) throw new NoSuchElementException();
+            advance();
+            return item;
+        }
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            l.item = null;
+            unlink(l);
+            lastRet = null;
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Itr() {}                        // prevent access constructor creation
+        Node<E> startNode() { return first(); }
+        Node<E> nextNode(Node<E> p) { return succ(p); }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        DescendingItr() {}              // prevent access constructor creation
+        Node<E> startNode() { return last(); }
+        Node<E> nextNode(Node<E> p) { return pred(p); }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    final class CLDSpliterator implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+
+        public Spliterator<E> trySplit() {
+            Node<E> p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final E e;
+                if ((e = p.item) != null) {
+                    if (a == null)
+                        a = new Object[n];
+                    a[i++] = e;
+                }
+                if (p == (p = q))
+                    p = first();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = current()) != null) {
+                current = null;
+                exhausted = true;
+                do {
+                    final E e;
+                    if ((e = p.item) != null)
+                        action.accept(e);
+                    if (p == (p = p.next))
+                        p = first();
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = current()) != null) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = first();
+                } while (e == null && p != null);
+                setCurrent(p);
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private void setCurrent(Node<E> p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node<E> current() {
+            Node<E> p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = first());
+            return p;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new CLDSpliterator();
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            final E item;
+            if ((item = p.item) != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = newNode((E) item);
+            if (h == null)
+                h = t = newNode;
+            else {
+                NEXT.set(t, newNode);
+                PREV.set(newNode, t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        for (Node<E> p = first(), succ; p != null; p = succ) {
+            succ = succ(p);
+            final E item;
+            if ((item = p.item) != null
+                && filter.test(item)
+                && ITEM.compareAndSet(p, item, null)) {
+                unlink(p);
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        E item;
+        for (Node<E> p = first(); p != null; p = succ(p))
+            if ((item = p.item) != null)
+                action.accept(item);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    private static final VarHandle PREV;
+    private static final VarHandle NEXT;
+    private static final VarHandle ITEM;
+    static {
+        PREV_TERMINATOR = new Node<Object>();
+        PREV_TERMINATOR.next = PREV_TERMINATOR;
+        NEXT_TERMINATOR = new Node<Object>();
+        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
+                                   Node.class);
+            PREV = l.findVarHandle(Node.class, "prev", Node.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/ConcurrentLinkedQueue.java b/android-35/java/util/concurrent/ConcurrentLinkedQueue.java
new file mode 100644
index 0000000..eac8ee7
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -0,0 +1,1075 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea 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/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * A {@code ConcurrentLinkedQueue} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>This implementation employs an efficient <em>non-blocking</em>
+ * algorithm based on one described in
+ * <a href="http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf">
+ * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
+ * Algorithms</a> by Maged M. Michael and Michael L. Scott.
+ *
+ * <p>Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the queue at some point at or since the
+ * creation of the iterator.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException}, and may proceed concurrently
+ * with other operations.  Elements contained in the queue since the creation
+ * of the iterator will be returned exactly once.
+ *
+ * <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.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe 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.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedQueue} in another thread.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 196745693267521676L;
+
+    /*
+     * This is a modification of the Michael & Scott algorithm,
+     * adapted for a garbage-collected environment, with support for
+     * interior node deletion (to support e.g. remove(Object)).  For
+     * explanation, read the paper.
+     *
+     * Note that like most non-blocking algorithms in this package,
+     * this implementation relies on the fact that in garbage
+     * collected systems, there is no possibility of ABA problems due
+     * to recycled nodes, so there is no need to use "counted
+     * pointers" or related techniques seen in versions used in
+     * non-GC'ed settings.
+     *
+     * The fundamental invariants are:
+     * - There is exactly one (last) Node with a null next reference,
+     *   which is CASed when enqueueing.  This last Node can be
+     *   reached in O(1) time from tail, but tail is merely an
+     *   optimization - it can always be reached in O(N) time from
+     *   head as well.
+     * - The elements contained in the queue are the non-null items in
+     *   Nodes that are reachable from head.  CASing the item
+     *   reference of a Node to null atomically removes it from the
+     *   queue.  Reachability of all elements from head must remain
+     *   true even in the case of concurrent modifications that cause
+     *   head to advance.  A dequeued Node may remain in use
+     *   indefinitely due to creation of an Iterator or simply a
+     *   poll() that has lost its time slice.
+     *
+     * The above might appear to imply that all Nodes are GC-reachable
+     * from a predecessor dequeued Node.  That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.
+     *
+     * Both head and tail are permitted to lag.  In fact, failing to
+     * update them every time one could is a significant optimization
+     * (fewer CASes). As with LinkedTransferQueue (see the internal
+     * documentation for that class), we use 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.
+     *
+     * Since head and tail are updated concurrently and independently,
+     * it is possible for tail to lag behind head (why not)?
+     *
+     * CASing a Node's item reference to null atomically removes the
+     * element from the queue, leaving a "dead" node that should later
+     * be unlinked (but unlinking is merely an optimization).
+     * Interior element removal methods (other than Iterator.remove())
+     * keep track of the predecessor node during traversal so that the
+     * node can be CAS-unlinked.  Some traversal methods try to unlink
+     * any deleted nodes encountered during traversal.  See comments
+     * in bulkRemove.
+     *
+     * When constructing a Node (before enqueuing it) we avoid paying
+     * for a volatile write to item.  This allows the cost of enqueue
+     * to be "one-and-a-half" CASes.
+     *
+     * Both head and tail may or may not point to a Node with a
+     * non-null item.  If the queue is empty, all items must of course
+     * be null.  Upon creation, both head and tail refer to a dummy
+     * Node with null item.  Both head and tail are only updated using
+     * CAS, so they never regress, although again this is merely an
+     * optimization.
+     */
+
+    static final class Node<E> {
+        volatile E item;
+        volatile Node<E> next;
+
+        /**
+         * Constructs a node holding item.  Uses relaxed write because
+         * item can only be seen after piggy-backing publication via CAS.
+         */
+        Node(E item) {
+            ITEM.set(this, item);
+        }
+
+        /** Constructs a dead dummy node. */
+        Node() {}
+
+        void appendRelaxed(Node<E> next) {
+            // assert next != null;
+            // assert this.next == null;
+            NEXT.set(this, next);
+        }
+
+        boolean casItem(E cmp, E val) {
+            // assert item == cmp || item == null;
+            // assert cmp != null;
+            // assert val == null;
+            return ITEM.compareAndSet(this, cmp, val);
+        }
+    }
+
+    /**
+     * A node from which the first live (non-deleted) node (if any)
+     * can be reached in O(1) time.
+     * Invariants:
+     * - all live nodes are reachable from head via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * Non-invariants:
+     * - head.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     */
+    transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique
+     * node with node.next == null) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always reachable from tail via succ()
+     * - tail != null
+     * Non-invariants:
+     * - tail.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     * - tail.next may or may not be self-linked.
+     */
+    private transient volatile Node<E> tail;
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
+     */
+    public ConcurrentLinkedQueue() {
+        head = tail = new Node<E>();
+    }
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue}
+     * 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 ConcurrentLinkedQueue(Collection<? extends E> c) {
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node<E>();
+        head = h;
+        tail = t;
+    }
+
+    // Have to override just to update the javadoc
+
+    /**
+     * 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) {
+        return offer(e);
+    }
+
+    /**
+     * Tries to CAS head to p. If successful, repoint old head to itself
+     * as sentinel for succ(), below.
+     */
+    final void updateHead(Node<E> h, Node<E> p) {
+        // assert h != null && p != null && (h == p || h.item == null);
+        if (h != p && HEAD.compareAndSet(this, h, p))
+            NEXT.setRelease(h, h);
+    }
+
+    /**
+     * 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<E> succ(Node<E> p) {
+        if (p == (p = p.next))
+            p = head;
+        return p;
+    }
+
+    /**
+     * Tries to CAS pred.next (or head, if pred is null) from c to p.
+     * Caller must ensure that we're not unlinking the trailing node.
+     */
+    private boolean tryCasSuccessor(Node<E> pred, Node<E> c, Node<E> p) {
+        // assert p != null;
+        // assert c.item == null;
+        // assert c != p;
+        if (pred != null)
+            return NEXT.compareAndSet(pred, c, p);
+        if (HEAD.compareAndSet(this, c, p)) {
+            NEXT.setRelease(c, c);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Collapse dead nodes between pred and q.
+     * @param pred the last known live node, or null if none
+     * @param c the first dead node
+     * @param p the last dead node
+     * @param q p.next: the next live node, or null if at end
+     * @return either old pred or p if pred dead or CAS failed
+     */
+    private Node<E> skipDeadNodes(Node<E> pred, Node<E> c, Node<E> p, Node<E> q) {
+        // assert pred != c;
+        // assert p != q;
+        // assert c.item == null;
+        // assert p.item == null;
+        if (q == null) {
+            // Never unlink trailing node.
+            if (c == p) return pred;
+            q = p;
+        }
+        return (tryCasSuccessor(pred, c, q)
+                && (pred == null || ITEM.get(pred) != null))
+            ? pred : p;
+    }
+
+    /**
+     * 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) {
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (NEXT.compareAndSet(p, null, newNode)) {
+                    // Successful CAS is the linearization point
+                    // for e to become an element of this queue,
+                    // and for newNode to become "live".
+                    if (p != t) // hop two nodes at a time; failure is OK
+                        TAIL.weakCompareAndSet(this, t, newNode);
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public E poll() {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
+                final E item;
+                if ((item = p.item) != null && p.casItem(item, null)) {
+                    // Successful CAS is the linearization point
+                    // for item to be removed from this queue.
+                    if (p != h) // hop two nodes at a time
+                        updateHead(h, ((q = p.next) != null) ? q : p);
+                    return item;
+                }
+                else if ((q = p.next) == null) {
+                    updateHead(h, p);
+                    return null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+            }
+        }
+    }
+
+    public E peek() {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
+                final E item;
+                if ((item = p.item) != null
+                    || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return item;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+            }
+        }
+    }
+
+    /**
+     * Returns the first live (non-deleted) node on list, or null if none.
+     * This is yet another variant of poll/peek; here returning the
+     * first node, not element.  We could make peek() a wrapper around
+     * first(), but that would cost an extra volatile read of item,
+     * and the need to add a retry loop to deal with the possibility
+     * of losing a race to a concurrent poll().
+     */
+    Node<E> first() {
+        restartFromHead: for (;;) {
+            for (Node<E> h = head, p = h, q;; p = q) {
+                boolean hasItem = (p.item != null);
+                if (hasItem || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return hasItem ? p : null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+            }
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return first() == 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.
+     * Additionally, if elements are added or removed during execution
+     * of this method, the returned result may be inaccurate.  Thus,
+     * this method is typically not very useful in concurrent
+     * applications.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * 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;
+        restartFromHead: for (;;) {
+            for (Node<E> p = head, pred = null; p != null; ) {
+                Node<E> q = p.next;
+                final E item;
+                if ((item = p.item) != null) {
+                    if (o.equals(item))
+                        return true;
+                    pred = p; p = q; continue;
+                }
+                for (Node<E> c = p;; q = p.next) {
+                    if (q == null || q.item != null) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
+            }
+            return 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) {
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node<E> p = head, pred = null; p != null; ) {
+                Node<E> q = p.next;
+                final E item;
+                if ((item = p.item) != null) {
+                    if (o.equals(item) && p.casItem(item, null)) {
+                        skipDeadNodes(pred, p, p, q);
+                        return true;
+                    }
+                    pred = p; p = q; continue;
+                }
+                for (Node<E> c = p;; q = p.next) {
+                    if (q == null || q.item != null) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this queue, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a queue to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this queue
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else
+                last.appendRelaxed(last = newNode);
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
+                    // Successful CAS is the linearization point
+                    // for all elements to be added to this queue.
+                    if (!TAIL.weakCompareAndSet(this, t, last)) {
+                        // Try a little harder to update tail,
+                        // since we may be adding many elements.
+                        t = tail;
+                        if (last.next == null)
+                            TAIL.weakCompareAndSet(this, t, last);
+                    }
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                final E item;
+                if ((item = p.item) != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        Objects.requireNonNull(a);
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * 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 href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node of the last returned item, to support remove.
+         */
+        private Node<E> lastRet;
+
+        Itr() {
+            restartFromHead: for (;;) {
+                Node<E> h, p, q;
+                for (p = h = head;; p = q) {
+                    final E item;
+                    if ((item = p.item) != null) {
+                        nextNode = p;
+                        nextItem = item;
+                        break;
+                    }
+                    else if ((q = p.next) == null)
+                        break;
+                    else if (p == q)
+                        continue restartFromHead;
+                }
+                updateHead(h, p);
+                return;
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            final Node<E> pred = nextNode;
+            if (pred == null) throw new NoSuchElementException();
+            // assert nextItem != null;
+            lastRet = pred;
+            E item = null;
+
+            for (Node<E> p = succ(pred), q;; p = q) {
+                if (p == null || (item = p.item) != null) {
+                    nextNode = p;
+                    E x = nextItem;
+                    nextItem = item;
+                    return x;
+                }
+                // unlink deleted nodes
+                if ((q = succ(p)) != null)
+                    NEXT.compareAndSet(pred, p, q);
+            }
+        }
+
+        // Default implementation of forEachRemaining is "good enough".
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            // rely on a future traversal to relink.
+            l.item = null;
+            lastRet = null;
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            final E item;
+            if ((item = p.item) != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = new Node<E>((E) item);
+            if (h == null)
+                h = t = newNode;
+            else
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node<E>();
+        head = h;
+        tail = t;
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    final class CLQSpliterator implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+
+        public Spliterator<E> trySplit() {
+            Node<E> p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final E e;
+                if ((e = p.item) != null) {
+                    if (a == null)
+                        a = new Object[n];
+                    a[i++] = e;
+                }
+                if (p == (p = q))
+                    p = first();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Node<E> p;
+            if ((p = current()) != null) {
+                current = null;
+                exhausted = true;
+                forEachFrom(action, p);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = current()) != null) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = first();
+                } while (e == null && p != null);
+                setCurrent(p);
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private void setCurrent(Node<E> p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node<E> current() {
+            Node<E> p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = first());
+            return p;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new CLQSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    public void clear() {
+        bulkRemove(e -> true);
+    }
+
+    /**
+     * Tolerate this many consecutive dead nodes before CAS-collapsing.
+     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+     */
+    private static final int MAX_HOPS = 8;
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        restartFromHead: for (;;) {
+            int hops = MAX_HOPS;
+            // c will be CASed to collapse intervening dead nodes between
+            // pred (or head if null) and p.
+            for (Node<E> p = head, c = p, pred = null, q; p != null; p = q) {
+                q = p.next;
+                final E item; boolean pAlive;
+                if (pAlive = ((item = p.item) != null)) {
+                    if (filter.test(item)) {
+                        if (p.casItem(item, null))
+                            removed = true;
+                        pAlive = false;
+                    }
+                }
+                if (pAlive || q == null || --hops == 0) {
+                    // p might already be self-linked here, but if so:
+                    // - CASing head will surely fail
+                    // - CASing pred's next will be useless but harmless.
+                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
+                        || pAlive) {
+                        // if CAS failed or alive, abandon old pred
+                        hops = MAX_HOPS;
+                        pred = p;
+                        c = q;
+                    }
+                } else if (p == q)
+                    continue restartFromHead;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, the action is not run.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        for (Node<E> pred = null; p != null; ) {
+            Node<E> q = p.next;
+            final E item;
+            if ((item = p.item) != null) {
+                action.accept(item);
+                pred = p; p = q; continue;
+            }
+            for (Node<E> c = p;; q = p.next) {
+                if (q == null || q.item != null) {
+                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                }
+                if (p == (p = q)) { pred = null; p = head; break; }
+            }
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, head);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    static final VarHandle ITEM;
+    static final VarHandle NEXT;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
+                                   Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/ConcurrentMap.java b/android-35/java/util/concurrent/ConcurrentMap.java
new file mode 100644
index 0000000..2037e31
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentMap.java
@@ -0,0 +1,500 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * A {@link Map} providing thread safety and atomicity guarantees.
+ *
+ * <p>To maintain the specified guarantees, default implementations of
+ * methods including {@link #putIfAbsent} inherited from {@link Map}
+ * must be overridden by implementations of this interface. Similarly,
+ * implementations of the collections returned by methods {@link
+ * #keySet}, {@link #values}, and {@link #entrySet} must override
+ * methods such as {@code removeIf} when necessary to
+ * preserve atomicity guarantees.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentMap} as a key or value
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that object from
+ * the {@code ConcurrentMap} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public interface ConcurrentMap<K,V> extends Map<K,V> {
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote This implementation assumes that the ConcurrentMap cannot
+     * contain null values and {@code get()} returning null unambiguously means
+     * the key is absent. Implementations which support null values
+     * <strong>must</strong> override this default implementation.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return ((v = get(key)) != null) ? v : defaultValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec The default implementation is equivalent to, for this
+     * {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   action.accept(entry.getKey(), entry.getValue());
+     * }}</pre>
+     *
+     * @implNote The default implementation assumes that
+     * {@code IllegalStateException} thrown by {@code getKey()} or
+     * {@code getValue()} indicates that the entry has been removed and cannot
+     * be processed. Operation continues for subsequent entries.
+     *
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K,V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                continue;
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * If the specified key is not already associated
+     * with a value, associates it with the given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (!map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return map.get(key);}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V putIfAbsent(K key, V value);
+
+    /**
+     * Removes the entry for a key only if currently mapped to a given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), value)) {
+     *   map.remove(key);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     * (<a href="{@docRoot}/java.base/java/util/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
+     * (<a href="{@docRoot}/java.base/java/util/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, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), oldValue)) {
+     *   map.put(key, newValue);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     */
+    boolean replace(K key, V oldValue, V newValue);
+
+    /**
+     * Replaces the entry for a key only if currently mapped to some value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return null;}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V replace(K key, V value);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   K k;
+     *   V v;
+     *   do {
+     *     k = entry.getKey();
+     *     v = entry.getValue();
+     *   } while (!map.replace(k, v, function.apply(k, v)));
+     * }}</pre>
+     *
+     * The default implementation may retry these steps when multiple
+     * threads attempt updates including potentially calling the function
+     * repeatedly for a given key.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        forEach((k,v) -> {
+            while (!replace(k, v, function.apply(k, v))) {
+                // v changed or k is gone
+                if ( (v = get(k)) == null) {
+                    // k is no longer in the map.
+                    break;
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}:
+     *
+     * <pre> {@code
+     * V oldValue, newValue;
+     * return ((oldValue = map.get(key)) == null
+     *         && (newValue = mappingFunction.apply(key)) != null
+     *         && (oldValue = map.putIfAbsent(key, newValue)) == null)
+     *   ? newValue
+     *   : oldValue;}</pre>
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V oldValue, newValue;
+        return ((oldValue = get(key)) == null
+                && (newValue = mappingFunction.apply(key)) != null
+                && (oldValue = putIfAbsent(key, newValue)) == null)
+            ? newValue
+            : oldValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (V oldValue; (oldValue = map.get(key)) != null; ) {
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if ((newValue == null)
+     *       ? map.remove(key, oldValue)
+     *       : map.replace(key, oldValue, newValue))
+     *     return newValue;
+     * }
+     * return null;}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        for (V oldValue; (oldValue = get(key)) != null; ) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if ((newValue == null)
+                ? remove(key, oldValue)
+                : replace(key, oldValue, newValue))
+                return newValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if (newValue != null) {
+     *     if ((oldValue != null)
+     *       ? map.replace(key, oldValue, newValue)
+     *       : map.putIfAbsent(key, newValue) == null)
+     *       return newValue;
+     *   } else if (oldValue == null || map.remove(key, oldValue)) {
+     *     return null;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V compute(K key,
+                      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                V newValue = remappingFunction.apply(key, oldValue);
+                if (newValue != null) {
+                    if (oldValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    }
+                    else if ((oldValue = putIfAbsent(key, newValue)) == null)
+                        return newValue;
+                    else continue haveOldValue;
+                } else if (oldValue == null || remove(key, oldValue)) {
+                    return null;
+                }
+                continue retry;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   if (oldValue != null) {
+     *     V newValue = remappingFunction.apply(oldValue, value);
+     *     if (newValue != null) {
+     *       if (map.replace(key, oldValue, newValue))
+     *         return newValue;
+     *     } else if (map.remove(key, oldValue)) {
+     *       return null;
+     *     }
+     *   } else if (map.putIfAbsent(key, value) == null) {
+     *     return value;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                if (oldValue != null) {
+                    V newValue = remappingFunction.apply(oldValue, value);
+                    if (newValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    } else if (remove(key, oldValue)) {
+                        return null;
+                    }
+                    continue retry;
+                } else {
+                    if ((oldValue = putIfAbsent(key, value)) == null)
+                        return value;
+                    continue haveOldValue;
+                }
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/ConcurrentNavigableMap.java b/android-35/java/util/concurrent/ConcurrentNavigableMap.java
new file mode 100644
index 0000000..1666c8b
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentNavigableMap.java
@@ -0,0 +1,169 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+
+/**
+ * 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}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface ConcurrentNavigableMap<K,V>
+    extends ConcurrentMap<K,V>, NavigableMap<K,V>
+{
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                       K toKey,   boolean toInclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link java.util.Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    ConcurrentNavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> keySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+}
diff --git a/android-35/java/util/concurrent/ConcurrentSkipListMap.java b/android-35/java/util/concurrent/ConcurrentSkipListMap.java
new file mode 100644
index 0000000..bccbccf
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentSkipListMap.java
@@ -0,0 +1,3443 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.concurrent.atomic.LongAdder;
+
+/**
+ * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This class implements a concurrent variant of <a
+ * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists</a>
+ * providing expected average <i>log(n)</i> time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and
+ * {@code remove} operations and their variants.  Insertion, removal,
+ * update, and access operations safely execute concurrently by
+ * multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending key ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <p>All {@code Map.Entry} pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <em>not</em> support the {@code Entry.setValue}
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using {@code put}, {@code putIfAbsent}, or
+ * {@code replace}, depending on exactly which effect you need.)
+ *
+ * <p>Beware that bulk operations {@code putAll}, {@code equals},
+ * {@code toArray}, {@code containsValue}, and {@code clear} are
+ * <em>not</em> guaranteed to be performed atomically. For example, an
+ * iterator operating concurrently with a {@code putAll} 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}
+ * interfaces. Like most other concurrent collections, this class does
+ * <em>not</em> permit the use of {@code null} keys or values because some
+ * null return values cannot be reliably distinguished from the absence of
+ * elements.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+    /*
+     * This class implements a tree-like two-dimensionally linked skip
+     * list in which the index levels are represented in separate
+     * nodes from the base nodes holding data.  There are two reasons
+     * for taking this approach instead of the usual array-based
+     * structure: 1) Array based implementations seem to encounter
+     * more complexity and overhead 2) We can use cheaper algorithms
+     * for the heavily-traversed index lists than can be used for the
+     * base lists.  Here's a picture of some of the basics for a
+     * possible list with 2 levels of index:
+     *
+     * Head nodes          Index nodes
+     * +-+    right        +-+                      +-+
+     * |2|---------------->| |--------------------->| |->null
+     * +-+                 +-+                      +-+
+     *  | down              |                        |
+     *  v                   v                        v
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     * |1|----------->| |->| |------>| |----------->| |------>| |->null
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     *  v              |    |         |              |         |
+     * Nodes  next     v    v         v              v         v
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     *
+     * The base lists use a variant of the HM linked ordered set
+     * algorithm. See Tim Harris, "A pragmatic implementation of
+     * non-blocking linked lists"
+     * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged
+     * Michael "High Performance Dynamic Lock-Free Hash Tables and
+     * List-Based Sets"
+     * http://www.research.ibm.com/people/m/michael/pubs.htm.  The
+     * basic idea in these lists is to mark the "next" pointers of
+     * deleted nodes when deleting to avoid conflicts with concurrent
+     * insertions, and when traversing to keep track of triples
+     * (predecessor, node, successor) in order to detect when and how
+     * to unlink these deleted nodes.
+     *
+     * Rather than using mark-bits to mark list deletions (which can
+     * be slow and space-intensive using AtomicMarkedReference), nodes
+     * use direct CAS'able next pointers.  On deletion, instead of
+     * marking a pointer, they splice in another node that can be
+     * thought of as standing for a marked pointer (see method
+     * unlinkNode).  Using plain nodes acts roughly like "boxed"
+     * implementations of marked pointers, but uses new nodes only
+     * when nodes are deleted, not for every link.  This requires less
+     * space and supports faster traversal. Even if marked references
+     * were better supported by JVMs, traversal using this technique
+     * might still be faster because any search need only read ahead
+     * one more node than otherwise required (to check for trailing
+     * marker) rather than unmasking mark bits or whatever on each
+     * read.
+     *
+     * This approach maintains the essential property needed in the HM
+     * algorithm of changing the next-pointer of a deleted node so
+     * that any other CAS of it will fail, but implements the idea by
+     * changing the pointer to point to a different node (with
+     * otherwise illegal null fields), not by marking it.  While it
+     * would be possible to further squeeze space by defining marker
+     * nodes not to have key/value fields, it isn't worth the extra
+     * type-testing overhead.  The deletion markers are rarely
+     * encountered during traversal, are easily detected via null
+     * checks that are needed anyway, and are normally quickly garbage
+     * collected. (Note that this technique would not work well in
+     * systems without garbage collection.)
+     *
+     * In addition to using deletion markers, the lists also use
+     * nullness of value fields to indicate deletion, in a style
+     * similar to typical lazy-deletion schemes.  If a node's value is
+     * null, then it is considered logically deleted and ignored even
+     * though it is still reachable.
+     *
+     * Here's the sequence of events for a deletion of node n with
+     * predecessor b and successor f, initially:
+     *
+     *        +------+       +------+      +------+
+     *   ...  |   b  |------>|   n  |----->|   f  | ...
+     *        +------+       +------+      +------+
+     *
+     * 1. CAS n's value field from non-null to null.
+     *    Traversals encountering a node with null value ignore it.
+     *    However, ongoing insertions and deletions might still modify
+     *    n's next pointer.
+     *
+     * 2. CAS n's next pointer to point to a new marker node.
+     *    From this point on, no other nodes can be appended to n.
+     *    which avoids deletion errors in CAS-based linked lists.
+     *
+     *        +------+       +------+      +------+       +------+
+     *   ...  |   b  |------>|   n  |----->|marker|------>|   f  | ...
+     *        +------+       +------+      +------+       +------+
+     *
+     * 3. CAS b's next pointer over both n and its marker.
+     *    From this point on, no new traversals will encounter n,
+     *    and it can eventually be GCed.
+     *        +------+                                    +------+
+     *   ...  |   b  |----------------------------------->|   f  | ...
+     *        +------+                                    +------+
+     *
+     * A failure at step 1 leads to simple retry due to a lost race
+     * with another operation. Steps 2-3 can fail because some other
+     * thread noticed during a traversal a node with null value and
+     * helped out by marking and/or unlinking.  This helping-out
+     * ensures that no thread can become stuck waiting for progress of
+     * the deleting thread.
+     *
+     * Skip lists add indexing to this scheme, so that the base-level
+     * traversals start close to the locations being found, inserted
+     * or deleted -- usually base level traversals only traverse a few
+     * nodes. This doesn't change the basic algorithm except for the
+     * need to make sure base traversals start at predecessors (here,
+     * b) that are not (structurally) deleted, otherwise retrying
+     * after processing the deletion.
+     *
+     * Index levels are maintained using CAS to link and unlink
+     * successors ("right" fields).  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node.
+     * (We can't do this of course for data nodes.)  However, even
+     * when this happens, the index lists correctly guide search.
+     * This can impact performance, but since skip lists are
+     * probabilistic anyway, the net result is that under contention,
+     * the effective "p" value may be lower than its nominal value.
+     *
+     * Index insertion and deletion sometimes require a separate
+     * traversal pass occurring after the base-level action, to add or
+     * remove index nodes.  This adds to single-threaded overhead, but
+     * improves contended multithreaded performance by narrowing
+     * interference windows, and allows deletion to ensure that all
+     * index nodes will be made unreachable upon return from a public
+     * remove operation, thus avoiding unwanted garbage retention.
+     *
+     * Indexing uses skip list parameters that maintain good search
+     * performance while using sparser-than-usual indices: The
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+     * about one-quarter of the nodes have indices. Of those that do,
+     * half have one level, a quarter have two, and so on (see Pugh's
+     * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+     * (appropriate for up to 2^63 elements).  The expected total
+     * space requirement for a map is slightly less than for the
+     * current implementation of java.util.TreeMap.
+     *
+     * Changing the level of the index (i.e, the height of the
+     * tree-like structure) also uses CAS.  Creation of an index with
+     * height greater than the current level adds a level to the head
+     * index by CAS'ing on a new top-most head. To maintain good
+     * performance after a lot of removals, deletion methods
+     * heuristically try to reduce the height if the topmost levels
+     * appear to be empty.  This may encounter races in which it is
+     * possible (but rare) to reduce and "lose" a level just as it is
+     * about to contain an index (that will then never be
+     * encountered). This does no structural harm, and in practice
+     * appears to be a better option than allowing unrestrained growth
+     * of levels.
+     *
+     * This class provides concurrent-reader-style memory consistency,
+     * ensuring that read-only methods report status and/or values no
+     * staler than those holding at method entry. This is done by
+     * performing all publication and structural updates using
+     * (volatile) CAS, placing an acquireFence in a few access
+     * methods, and ensuring that linked objects are transitively
+     * acquired via dependent reads (normally once) unless performing
+     * a volatile-mode CAS operation (that also acts as an acquire and
+     * release).  This form of fence-hoisting is similar to RCU and
+     * related techniques (see McKenney's online book
+     * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+     * It minimizes overhead that may otherwise occur when using so
+     * many volatile-mode reads. Using explicit acquireFences is
+     * logistically easier than targeting particular fields to be read
+     * in acquire mode: fences are just hoisted up as far as possible,
+     * to the entry points or loop headers of a few methods. A
+     * potential disadvantage is that these few remaining fences are
+     * not easily optimized away by compilers under exclusively
+     * single-thread use.  It requires some care to avoid volatile
+     * mode reads of other fields. (Note that the memory semantics of
+     * a reference dependently read in plain mode exactly once are
+     * equivalent to those for atomic opaque mode.)  Iterators and
+     * other traversals encounter each node and value exactly once.
+     * Other operations locate an element (or position to insert an
+     * element) via a sequence of dereferences. This search is broken
+     * into two parts. Method findPredecessor (and its specialized
+     * embeddings) searches index nodes only, returning a base-level
+     * predecessor of the key. Callers carry out the base-level
+     * search, restarting if encountering a marker preventing link
+     * modification.  In some cases, it is possible to encounter a
+     * node multiple times while descending levels. For mutative
+     * operations, the reported value is validated using CAS (else
+     * retrying), preserving linearizability with respect to each
+     * other. Others may return any (non-null) value holding in the
+     * course of the method call.  (Search-based methods also include
+     * some useless-looking explicit null checks designed to allow
+     * more fields to be nulled out upon removal, to reduce floating
+     * garbage, but which is not currently done, pending discovery of
+     * a way to do this with less impact on other operations.)
+     *
+     * To produce random values without interference across threads,
+     * we use within-JDK thread local random support (via the
+     * "secondary seed", to avoid interference with user-level
+     * ThreadLocalRandom.)
+     *
+     * For explanation of algorithms sharing at least a couple of
+     * features with this one, see Mikhail Fomitchev's thesis
+     * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
+     * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
+     * thesis (http://www.cs.chalmers.se/~phs/).
+     *
+     * Notation guide for local variables
+     * Node:         b, n, f, p for  predecessor, node, successor, aux
+     * Index:        q, r, d    for index node, right, down.
+     * Head:         h
+     * Keys:         k, key
+     * Values:       v, value
+     * Comparisons:  c
+     */
+
+    private static final long serialVersionUID = -8627078645895051609L;
+
+    /**
+     * The comparator used to maintain order in this map, or null if
+     * using natural ordering.  (Non-private to simplify access in
+     * nested classes.)
+     * @serial
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    final Comparator<? super K> comparator;
+
+    /** Lazily initialized topmost index of the skiplist. */
+    private transient Index<K,V> head;
+    /** Lazily initialized element count */
+    private transient LongAdder adder;
+    /** Lazily initialized key set */
+    private transient KeySet<K,V> keySet;
+    /** Lazily initialized values collection */
+    private transient Values<K,V> values;
+    /** Lazily initialized entry set */
+    private transient EntrySet<K,V> entrySet;
+    /** Lazily initialized descending map */
+    private transient SubMap<K,V> descendingMap;
+
+    /**
+     * Nodes hold keys and values, and are singly linked in sorted
+     * order, possibly with some intervening marker nodes. The list is
+     * headed by a header node accessible as head.node. Headers and
+     * marker nodes have null keys. The val field (but currently not
+     * the key field) is nulled out upon deletion.
+     */
+    static final class Node<K,V> {
+        final K key; // currently, never detached
+        V val;
+        Node<K,V> next;
+        Node(K key, V value, Node<K,V> next) {
+            this.key = key;
+            this.val = value;
+            this.next = next;
+        }
+    }
+
+    /**
+     * Index nodes represent the levels of the skip list.
+     */
+    static final class Index<K,V> {
+        final Node<K,V> node;  // currently, never detached
+        final Index<K,V> down;
+        Index<K,V> right;
+        Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
+            this.node = node;
+            this.down = down;
+            this.right = right;
+        }
+    }
+
+    /* ----------------  Utilities -------------- */
+
+    /**
+     * Compares using comparator or natural ordering if null.
+     * Called only by methods that have performed required type checks.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    static int cpr(Comparator c, Object x, Object y) {
+        return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
+    }
+
+    /**
+     * Returns the header for base node list, or null if uninitialized
+     */
+    final Node<K,V> baseHead() {
+        Index<K,V> h;
+        VarHandle.acquireFence();
+        return ((h = head) == null) ? null : h.node;
+    }
+
+    /**
+     * Tries to unlink deleted node n from predecessor b (if both
+     * exist), by first splicing in a marker if not already present.
+     * Upon return, node n is sure to be unlinked from b, possibly
+     * via the actions of some other thread.
+     *
+     * @param b if nonnull, predecessor
+     * @param n if nonnull, node known to be deleted
+     */
+    static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
+        if (b != null && n != null) {
+            Node<K,V> f, p;
+            for (;;) {
+                if ((f = n.next) != null && f.key == null) {
+                    p = f.next;               // already marked
+                    break;
+                }
+                else if (NEXT.compareAndSet(n, f,
+                                            new Node<K,V>(null, null, f))) {
+                    p = f;                    // add marker
+                    break;
+                }
+            }
+            NEXT.compareAndSet(b, n, p);
+        }
+    }
+
+    /**
+     * Adds to element count, initializing adder if necessary
+     *
+     * @param c count to add
+     */
+    private void addCount(long c) {
+        LongAdder a;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        a.add(c);
+    }
+
+    /**
+     * Returns element count, initializing adder if necessary.
+     */
+    final long getAdderCount() {
+        LongAdder a; long c;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
+    }
+
+    /* ---------------- Traversal -------------- */
+
+    /**
+     * Returns an index node with key strictly less than given key.
+     * Also unlinks indexes to deleted nodes found along the way.
+     * Callers rely on this side-effect of clearing indices to deleted
+     * nodes.
+     *
+     * @param key if nonnull the key
+     * @return a predecessor node of key, or null if uninitialized or null key
+     */
+    private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
+        if ((q = head) == null || key == null)
+            return null;
+        else {
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null)  // unlink index to deleted node
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (cpr(cmp, key, k) > 0)
+                        q = r;
+                    else
+                        break;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else
+                    return q.node;
+            }
+        }
+    }
+
+    /**
+     * Returns node holding key or null if no such, clearing out any
+     * deleted nodes seen along the way.  Repeatedly traverses at
+     * base-level looking for key starting at predecessor returned
+     * from findPredecessor, processing base-level deletions as
+     * encountered. Restarts occur, at traversal step encountering
+     * node n, if n's key field is null, indicating it is a marker, so
+     * its predecessor is deleted before continuing, which we help do
+     * by re-finding a valid predecessor.  The traversal loops in
+     * doPut, doRemove, and findNear all include the same checks.
+     *
+     * @param key the key
+     * @return node holding key, or null if no such
+     */
+    private Node<K,V> findNode(Object key) {
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        Comparator<? super K> cmp = comparator;
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
+                    break outer;               // empty
+                else if ((k = n.key) == null)
+                    break;                     // b is deleted
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);          // n is deleted
+                else if ((c = cpr(cmp, key, k)) > 0)
+                    b = n;
+                else if (c == 0)
+                    return n;
+                else
+                    break outer;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets value for key. Same idea as findNode, except skips over
+     * deletions and markers, and returns first encountered value to
+     * avoid possibly inconsistent rereads.
+     *
+     * @param key the key
+     * @return the value, or null if absent
+     */
+    private V doGet(Object key) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        V result = null;
+        if ((q = head) != null) {
+            outer: for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k; V v; int c;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        (v = p.val) == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0) {
+                        result = v;
+                        break outer;
+                    }
+                    else
+                        break;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    Node<K,V> b, n;
+                    if ((b = q.node) != null) {
+                        while ((n = b.next) != null) {
+                            V v; int c;
+                            K k = n.key;
+                            if ((v = n.val) == null || k == null ||
+                                (c = cpr(cmp, key, k)) > 0)
+                                b = n;
+                            else {
+                                if (c == 0)
+                                    result = v;
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /* ---------------- Insertion -------------- */
+
+    /**
+     * Main insertion method.  Adds element if not present, or
+     * replaces value if present and onlyIfAbsent is false.
+     *
+     * @param key the key
+     * @param value the value that must be associated with key
+     * @param onlyIfAbsent if should not insert if already present
+     * @return the old value, or null if newly inserted
+     */
+    private V doPut(K key, V value, boolean onlyIfAbsent) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            Index<K,V> h; Node<K,V> b;
+            VarHandle.acquireFence();
+            int levels = 0;                    // number of levels descended
+            if ((h = head) == null) {          // try to initialize
+                Node<K,V> base = new Node<K,V>(null, null, null);
+                h = new Index<K,V>(base, null, null);
+                b = (HEAD.compareAndSet(this, null, h)) ? base : null;
+            }
+            else {
+                for (Index<K,V> q = h, r, d;;) { // count while descending
+                    while ((r = q.right) != null) {
+                        Node<K,V> p; K k;
+                        if ((p = r.node) == null || (k = p.key) == null ||
+                            p.val == null)
+                            RIGHT.compareAndSet(q, r, r.right);
+                        else if (cpr(cmp, key, k) > 0)
+                            q = r;
+                        else
+                            break;
+                    }
+                    if ((d = q.down) != null) {
+                        ++levels;
+                        q = d;
+                    }
+                    else {
+                        b = q.node;
+                        break;
+                    }
+                }
+            }
+            if (b != null) {
+                Node<K,V> z = null;              // new node, if inserted
+                for (;;) {                       // find insertion point
+                    Node<K,V> n, p; K k; V v; int c;
+                    if ((n = b.next) == null) {
+                        if (b.key == null)       // if empty, type check key now
+                            cpr(cmp, key, key);
+                        c = -1;
+                    }
+                    else if ((k = n.key) == null)
+                        break;                   // can't append; restart
+                    else if ((v = n.val) == null) {
+                        unlinkNode(b, n);
+                        c = 1;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        b = n;
+                    else if (c == 0 &&
+                             (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
+                        return v;
+
+                    if (c < 0 &&
+                        NEXT.compareAndSet(b, n,
+                                           p = new Node<K,V>(key, value, n))) {
+                        z = p;
+                        break;
+                    }
+                }
+
+                if (z != null) {
+                    int lr = ThreadLocalRandom.nextSecondarySeed();
+                    if ((lr & 0x3) == 0) {       // add indices with 1/4 prob
+                        int hr = ThreadLocalRandom.nextSecondarySeed();
+                        long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
+                        int skips = levels;      // levels to descend before add
+                        Index<K,V> x = null;
+                        for (;;) {               // create at most 62 indices
+                            x = new Index<K,V>(z, x, null);
+                            if (rnd >= 0L || --skips < 0)
+                                break;
+                            else
+                                rnd <<= 1;
+                        }
+                        if (addIndices(h, skips, x, cmp) && skips < 0 &&
+                            head == h) {         // try to add new level
+                            Index<K,V> hx = new Index<K,V>(z, x, null);
+                            Index<K,V> nh = new Index<K,V>(h.node, h, hx);
+                            HEAD.compareAndSet(this, h, nh);
+                        }
+                        if (z.val == null)       // deleted while adding indices
+                            findPredecessor(key, cmp); // clean
+                    }
+                    addCount(1L);
+                    return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Add indices after an insertion. Descends iteratively to the
+     * highest level of insertion, then recursively, to chain index
+     * nodes to lower ones. Returns null on (staleness) failure,
+     * disabling higher-level insertions. Recursion depths are
+     * exponentially less probable.
+     *
+     * @param q starting index for current level
+     * @param skips levels to skip before inserting
+     * @param x index for this insertion
+     * @param cmp comparator
+     */
+    static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
+                                    Comparator<? super K> cmp) {
+        Node<K,V> z; K key;
+        if (x != null && (z = x.node) != null && (key = z.key) != null &&
+            q != null) {                            // hoist checks
+            boolean retrying = false;
+            for (;;) {                              // find splice point
+                Index<K,V> r, d; int c;
+                if ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null) {
+                        RIGHT.compareAndSet(q, r, r.right);
+                        c = 0;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0)
+                        break;                      // stale
+                }
+                else
+                    c = -1;
+
+                if (c < 0) {
+                    if ((d = q.down) != null && skips > 0) {
+                        --skips;
+                        q = d;
+                    }
+                    else if (d != null && !retrying &&
+                             !addIndices(d, 0, x.down, cmp))
+                        break;
+                    else {
+                        x.right = r;
+                        if (RIGHT.compareAndSet(q, r, x))
+                            return true;
+                        else
+                            retrying = true;         // re-find splice point
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /* ---------------- Deletion -------------- */
+
+    /**
+     * Main deletion method. Locates node, nulls value, appends a
+     * deletion marker, unlinks predecessor, removes associated index
+     * nodes, and possibly reduces head index level.
+     *
+     * @param key the key
+     * @param value if non-null, the value that must be
+     * associated with key
+     * @return the node, or null if not found
+     */
+    final V doRemove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        V result = null;
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null &&
+                      result == null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
+                    break outer;
+                else if ((k = n.key) == null)
+                    break;
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else if ((c = cpr(cmp, key, k)) > 0)
+                    b = n;
+                else if (c < 0)
+                    break outer;
+                else if (value != null && !value.equals(v))
+                    break outer;
+                else if (VAL.compareAndSet(n, v, null)) {
+                    result = v;
+                    unlinkNode(b, n);
+                    break; // loop to clean up
+                }
+            }
+        }
+        if (result != null) {
+            tryReduceLevel();
+            addCount(-1L);
+        }
+        return result;
+    }
+
+    /**
+     * Possibly reduce head level if it has no nodes.  This method can
+     * (rarely) make mistakes, in which case levels can disappear even
+     * though they are about to contain index nodes. This impacts
+     * performance, not correctness.  To minimize mistakes as well as
+     * to reduce hysteresis, the level is reduced by one only if the
+     * topmost three levels look empty. Also, if the removed level
+     * looks non-empty after CAS, we try to change it back quick
+     * before anyone notices our mistake! (This trick works pretty
+     * well because this method will practically never make mistakes
+     * unless current thread stalls immediately before first CAS, in
+     * which case it is very unlikely to stall again immediately
+     * afterwards, so will recover.)
+     *
+     * We put up with all this rather than just let levels grow
+     * because otherwise, even a small map that has undergone a large
+     * number of insertions and removals will have a lot of levels,
+     * slowing down access more than would an occasional unwanted
+     * reduction.
+     */
+    private void tryReduceLevel() {
+        Index<K,V> h, d, e;
+        if ((h = head) != null && h.right == null &&
+            (d = h.down) != null && d.right == null &&
+            (e = d.down) != null && e.right == null &&
+            HEAD.compareAndSet(this, h, d) &&
+            h.right != null)   // recheck
+            HEAD.compareAndSet(this, d, h);  // try to backout
+    }
+
+    /* ---------------- Finding and removing first element -------------- */
+
+    /**
+     * Gets first valid node, unlinking deleted nodes if encountered.
+     * @return first node or null if empty
+     */
+    final Node<K,V> findFirst() {
+        Node<K,V> b, n;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if (n.val == null)
+                    unlinkNode(b, n);
+                else
+                    return n;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Entry snapshot version of findFirst
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes first entry; returns its snapshot.
+     * @return null if empty, else snapshot of first entry
+     */
+    private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
+                    K k = n.key;
+                    unlinkNode(b, n);
+                    if (v != null) {
+                        tryReduceLevel();
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Finding and removing last element -------------- */
+
+    /**
+     * Specialized version of find to get last valid node.
+     * @return last node or null if empty
+     */
+    final Node<K,V> findLast() {
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p;
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else
+                        q = r;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    b = q.node;
+                    break;
+                }
+            }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            return b;
+                    }
+                    else if (n.key == null)
+                        break;
+                    else if (n.val == null)
+                        unlinkNode(b, n);
+                    else
+                        b = n;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Entry version of findLast
+     * @return Entry for last node or null if empty
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
+        for (;;) {
+            Node<K,V> n; V v;
+            if ((n = findLast()) == null)
+                return null;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+        }
+    }
+
+    /**
+     * Removes last entry; returns its snapshot.
+     * Specialized variant of doRemove.
+     * @return null if empty, else snapshot of last entry
+     */
+    private Map.Entry<K,V> doRemoveLastEntry() {
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
+            for (;;) {
+                Index<K,V> d, r; Node<K,V> p;
+                while ((r = q.right) != null) {
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (p.next != null)
+                        q = r;  // continue only if a successor
+                    else
+                        break;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    b = q.node;
+                    break;
+                }
+            }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n; K k; V v;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            break; // retry
+                    }
+                    else if ((k = n.key) == null)
+                        break;
+                    else if ((v = n.val) == null)
+                        unlinkNode(b, n);
+                    else if (n.next != null)
+                        b = n;
+                    else if (VAL.compareAndSet(n, v, null)) {
+                        unlinkNode(b, n);
+                        tryReduceLevel();
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    // Control values OR'ed as arguments to findNear
+
+    private static final int EQ = 1;
+    private static final int LT = 2;
+    private static final int GT = 0; // Actually checked as !LT
+
+    /**
+     * Utility for ceiling, floor, lower, higher methods.
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return nearest node fitting relation, or null if no such
+     */
+    final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
+        if (key == null)
+            throw new NullPointerException();
+        Node<K,V> result;
+        outer: for (Node<K,V> b;;) {
+            if ((b = findPredecessor(key, cmp)) == null) {
+                result = null;
+                break;                   // empty
+            }
+            for (;;) {
+                Node<K,V> n; K k; int c;
+                if ((n = b.next) == null) {
+                    result = ((rel & LT) != 0 && b.key != null) ? b : null;
+                    break outer;
+                }
+                else if ((k = n.key) == null)
+                    break;
+                else if (n.val == null)
+                    unlinkNode(b, n);
+                else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
+                         (c < 0 && (rel & LT) == 0)) {
+                    result = n;
+                    break outer;
+                }
+                else if (c <= 0 && (rel & LT) != 0) {
+                    result = (b.key != null) ? b : null;
+                    break outer;
+                }
+                else
+                    b = n;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Variant of findNear returning SimpleImmutableEntry
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return Entry fitting relation, or null if no such
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
+                                                              Comparator<? super K> cmp) {
+        for (;;) {
+            Node<K,V> n; V v;
+            if ((n = findNear(key, rel, cmp)) == null)
+                return null;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+        }
+    }
+
+    /* ---------------- Constructors -------------- */
+
+    /**
+     * Constructs a new, empty map, sorted according to the
+     * {@linkplain Comparable natural ordering} of the keys.
+     */
+    public ConcurrentSkipListMap() {
+        this.comparator = null;
+    }
+
+    /**
+     * Constructs a new, empty map, sorted according to the specified
+     * comparator.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public ConcurrentSkipListMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+    }
+
+    /**
+     * Constructs a new map containing the same mappings as the given map,
+     * sorted according to the {@linkplain Comparable natural ordering} of
+     * the keys.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in {@code m} are not
+     *         {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified map or any of its keys
+     *         or values are null
+     */
+    public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
+        this.comparator = null;
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new map containing the same mappings and using the
+     * same ordering as the specified sorted map.
+     *
+     * @param m the sorted map whose mappings are to be placed in this
+     *        map, and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified sorted map or any of
+     *         its keys or values are null
+     */
+    public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
+        this.comparator = m.comparator();
+        buildFromSorted(m); // initializes transients
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListMap}
+     * instance. (The keys and values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public ConcurrentSkipListMap<K,V> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListMap<K,V> clone =
+                (ConcurrentSkipListMap<K,V>) super.clone();
+            clone.keySet = null;
+            clone.entrySet = null;
+            clone.values = null;
+            clone.descendingMap = null;
+            clone.adder = null;
+            clone.buildFromSorted(this);
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Streamlined bulk insertion to initialize from elements of
+     * given sorted map.  Call only from constructor or clone
+     * method.
+     */
+    private void buildFromSorted(SortedMap<K, ? extends V> map) {
+        if (map == null)
+            throw new NullPointerException();
+        Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
+            map.entrySet().iterator();
+
+        /*
+         * Add equally spaced indices at log intervals, using the bits
+         * of count during insertion. The maximum possible resulting
+         * level is less than the number of bits in a long (64). The
+         * preds array tracks the current rightmost node at each
+         * level.
+         */
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        long count = 0;
+
+        while (it.hasNext()) {
+            Map.Entry<? extends K, ? extends V> e = it.next();
+            K k = e.getKey();
+            V v = e.getValue();
+            if (k == null || v == null)
+                throw new NullPointerException();
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
+                do {
+                    idx = new Index<K,V>(z, idx, null);
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
+            }
+        }
+        if (count != 0L) {
+            VarHandle.releaseFence(); // emulate volatile stores
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
+    }
+
+    /* ---------------- Serialization -------------- */
+
+    /**
+     * Saves this map to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The key (Object) and value (Object) for each
+     * key-value mapping represented by the map, followed by
+     * {@code null}. The key-value mappings are emitted in key-order
+     * (as determined by the Comparator, or by the keys' natural
+     * ordering if no Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out keys and values (alternating)
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    s.writeObject(n.key);
+                    s.writeObject(v);
+                }
+                b = n;
+            }
+        }
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this map from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+
+        // Same idea as buildFromSorted
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        Comparator<? super K> cmp = comparator;
+        K prevKey = null;
+        long count = 0;
+
+        for (;;) {
+            K k = (K)s.readObject();
+            if (k == null)
+                break;
+            V v = (V)s.readObject();
+            if (v == null)
+                throw new NullPointerException();
+            if (prevKey != null && cpr(cmp, prevKey, k) > 0)
+                throw new IllegalStateException("out of order");
+            prevKey = k;
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
+                do {
+                    idx = new Index<K,V>(z, idx, null);
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
+            }
+        }
+        if (count != 0L) {
+            VarHandle.releaseFence();
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
+    }
+
+    /* ------ Map API methods ------ */
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return doGet(key) != null;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        return doGet(key);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or the given defaultValue if this map contains no mapping for the key.
+     *
+     * @param key the key
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the defaultValue
+     * @throws NullPointerException if the specified key is null
+     * @since 1.8
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = doGet(key)) == null ? defaultValue : v;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, false);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return doRemove(key, null);
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  This operation requires time linear in the
+     * 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 {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && value.equals(v))
+                    return true;
+                else
+                    b = n;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        long c;
+        return ((baseHead() == null) ? 0 :
+                ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
+                Integer.MAX_VALUE : (int) c);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return findFirst() == null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        Index<K,V> h, r, d; Node<K,V> b;
+        VarHandle.acquireFence();
+        while ((h = head) != null) {
+            if ((r = h.right) != null)        // remove indices
+                RIGHT.compareAndSet(h, r, null);
+            else if ((d = h.down) != null)    // remove levels
+                HEAD.compareAndSet(this, h, d);
+            else {
+                long count = 0L;
+                if ((b = h.node) != null) {    // remove nodes
+                    Node<K,V> n; V v;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null &&
+                            VAL.compareAndSet(n, v, null)) {
+                            --count;
+                            v = null;
+                        }
+                        if (v == null)
+                            unlinkNode(b, n);
+                    }
+                }
+                if (count != 0L)
+                    addCount(count);
+                else
+                    break;
+            }
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The function
+     * is <em>NOT</em> guaranteed to be applied once atomically only
+     * if the value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null
+     *         or the mappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        V v, p, r;
+        if ((v = doGet(key)) == null &&
+            (r = mappingFunction.apply(key)) != null)
+            v = (p = doPut(key, r, true)) == null ? r : p;
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value. The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> n; V v;
+        while ((n = findNode(key)) != null) {
+            if ((v = n.val) != null) {
+                V r = remappingFunction.apply(key, v);
+                if (r != null) {
+                    if (VAL.compareAndSet(n, v, r))
+                        return r;
+                }
+                else if (doRemove(key, v) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; V v; V r;
+            if ((n = findNode(key)) == null) {
+                if ((r = remappingFunction.apply(key, null)) == null)
+                    break;
+                if (doPut(key, r, true) == null)
+                    return r;
+            }
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(key, v)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
+                        return r;
+                }
+                else if (doRemove(key, v) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * associates it with the given value.  Otherwise, replaces the
+     * value with the results of the given remapping function, or
+     * removes if {@code null}. The function is <em>NOT</em>
+     * guaranteed to be applied once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or value is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; V v; V r;
+            if ((n = findNode(key)) == null) {
+                if (doPut(key, value, true) == null)
+                    return value;
+            }
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(v, value)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
+                        return r;
+                }
+                else if (doRemove(key, v) != null)
+                    return null;
+            }
+        }
+    }
+
+    /* ---------------- View methods -------------- */
+
+    /*
+     * Note: Lazy initialization works for views because view classes
+     * are stateless/immutable so it doesn't matter wrt correctness if
+     * more than one is created (which will only rarely happen).  Even
+     * so, the following idiom conservatively ensures that the method
+     * returns the one it created if it does so, not one created by
+     * another racing thread.
+     */
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.
+     *
+     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+     * is {@code null} if the {@linkplain #comparator() map's comparator}
+     * is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    public NavigableSet<K> keySet() {
+        KeySet<K,V> ks;
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySet<>(this);
+    }
+
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K,V> ks;
+        if ((ks = keySet) != null) return ks;
+        return keySet = new KeySet<>(this);
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collections's spliterator additionally
+     * reports {@link Spliterator#CONCURRENT}, {@link Spliterator#NONNULL} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * order of the corresponding keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     */
+    public Collection<V> values() {
+        Values<K,V> vs;
+        if ((vs = values) != null) return vs;
+        return values = new Values<>(this);
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order.  The
+     * set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll} and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Map.Entry} elements traversed by the {@code iterator}
+     * or {@code spliterator} do <em>not</em> support the {@code setValue}
+     * operation.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet<K,V> es;
+        if ((es = entrySet) != null) return es;
+        return entrySet = new EntrySet<K,V>(this);
+    }
+
+    public ConcurrentNavigableMap<K,V> descendingMap() {
+        ConcurrentNavigableMap<K,V> dm;
+        if ((dm = descendingMap) != null) return dm;
+        return descendingMap =
+            new SubMap<K,V>(this, null, false, null, false, true);
+    }
+
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /* ---------------- AbstractMap Overrides -------------- */
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is also a map and the
+     * two maps represent the same mappings.  More formally, two maps
+     * {@code m1} and {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This
+     * operation may return misleading results if either map is
+     * concurrently modified during execution of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> m = (Map<?,?>) o;
+        try {
+            Comparator<? super K> cmp = comparator;
+            // See JDK-8223553 for Iterator type wildcard rationale
+            Iterator<? extends Map.Entry<?,?>> it = m.entrySet().iterator();
+            if (m instanceof SortedMap &&
+                ((SortedMap<?,?>)m).comparator() == cmp) {
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    while ((n = b.next) != null) {
+                        K k; V v;
+                        if ((v = n.val) != null && (k = n.key) != null) {
+                            if (!it.hasNext())
+                                return false;
+                            Map.Entry<?,?> e = it.next();
+                            Object mk = e.getKey();
+                            Object mv = e.getValue();
+                            if (mk == null || mv == null)
+                                return false;
+                            try {
+                                if (cpr(cmp, k, mk) != 0)
+                                    return false;
+                            } catch (ClassCastException cce) {
+                                return false;
+                            }
+                            if (!mv.equals(v))
+                                return false;
+                        }
+                        b = n;
+                    }
+                }
+                return !it.hasNext();
+            }
+            else {
+                while (it.hasNext()) {
+                    V v;
+                    Map.Entry<?,?> e = it.next();
+                    Object mk = e.getKey();
+                    Object mv = e.getValue();
+                    if (mk == null || mv == null ||
+                        (v = get(mk)) == null || !v.equals(mv))
+                        return false;
+                }
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    K k; V v; Object mv;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null && (k = n.key) != null &&
+                            ((mv = m.get(k)) == null || !mv.equals(v)))
+                            return false;
+                        b = n;
+                    }
+                }
+                return true;
+            }
+        } catch (ClassCastException | NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /* ------ ConcurrentMap API methods ------ */
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && doRemove(key, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; V v;
+            if ((n = findNode(key)) == null)
+                return false;
+            if ((v = n.val) != null) {
+                if (!oldValue.equals(v))
+                    return false;
+                if (VAL.compareAndSet(n, v, newValue))
+                    return true;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; V v;
+            if ((n = findNode(key)) == null)
+                return null;
+            if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
+                return v;
+        }
+    }
+
+    /* ------ SortedMap API methods ------ */
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        Node<K,V> n = findFirst();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        Node<K,V> n = findLast();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+   /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+     public V putFirst(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * map's comparison method determines the position of mappings, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public V putLast(K k, V v) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey,
+                                              boolean fromInclusive,
+                                              K toKey,
+                                              boolean toInclusive) {
+        if (fromKey == null || toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, fromInclusive, toKey, toInclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey,
+                                               boolean inclusive) {
+        if (toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, null, false, toKey, inclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey,
+                                               boolean inclusive) {
+        if (fromKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, inclusive, null, false, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key. The returned entry does <em>not</em> support the
+     * {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return findNearEntry(key, LT, comparator);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K lowerKey(K key) {
+        Node<K,V> n = findNear(key, LT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return findNearEntry(key, LT|EQ, comparator);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K floorKey(K key) {
+        Node<K,V> n = findNear(key, LT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such entry. The returned entry does <em>not</em>
+     * support the {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return findNearEntry(key, GT|EQ, comparator);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K ceilingKey(K key) {
+        Node<K,V> n = findNear(key, GT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return findNearEntry(key, GT, comparator);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K higherKey(K key) {
+        Node<K,V> n = findNear(key, GT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> firstEntry() {
+        return findFirstEntry();
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> lastEntry() {
+        return findLastEntry();
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        return doRemoveFirstEntry();
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        return doRemoveLastEntry();
+    }
+
+    /* ---------------- Iterators -------------- */
+
+    /**
+     * Base of iterator classes
+     */
+    abstract class Iter<T> implements Iterator<T> {
+        /** the last node returned by next() */
+        Node<K,V> lastReturned;
+        /** the next node to return from next(); */
+        Node<K,V> next;
+        /** Cache of next value field to maintain weak consistency */
+        V nextValue;
+
+        /** Initializes ascending iterator for entire range. */
+        Iter() {
+            advance(baseHead());
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        /** Advances next to higher entry. */
+        final void advance(Node<K,V> b) {
+            Node<K,V> n = null;
+            V v = null;
+            if ((lastReturned = b) != null) {
+                while ((n = b.next) != null && (v = n.val) == null)
+                    b = n;
+            }
+            nextValue = v;
+            next = n;
+        }
+
+        public final void remove() {
+            Node<K,V> n; K k;
+            if ((n = lastReturned) == null || (k = n.key) == null)
+                throw new IllegalStateException();
+            // It would not be worth all of the overhead to directly
+            // unlink from here. Using remove is fast enough.
+            ConcurrentSkipListMap.this.remove(k);
+            lastReturned = null;
+        }
+    }
+
+    final class ValueIterator extends Iter<V> {
+        public V next() {
+            V v;
+            if ((v = nextValue) == null)
+                throw new NoSuchElementException();
+            advance(next);
+            return v;
+        }
+    }
+
+    final class KeyIterator extends Iter<K> {
+        public K next() {
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
+            advance(n);
+            return k;
+        }
+    }
+
+    final class EntryIterator extends Iter<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
+            V v = nextValue;
+            advance(n);
+            return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+        }
+    }
+
+    /* ---------------- View Classes -------------- */
+
+    /*
+     * View classes are static, delegating to a ConcurrentNavigableMap
+     * to allow use by SubMaps, which outweighs the ugliness of
+     * needing type-tests for Iterator methods.
+     */
+
+    static final <E> List<E> toList(Collection<E> c) {
+        // Using size() here would be a pessimization.
+        ArrayList<E> list = new ArrayList<E>();
+        for (E e : c)
+            list.add(e);
+        return list;
+    }
+
+    static final class KeySet<K,V>
+            extends AbstractSet<K> implements NavigableSet<K> {
+        final ConcurrentNavigableMap<K,V> m;
+        KeySet(ConcurrentNavigableMap<K,V> map) { m = map; }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o) { return m.remove(o) != null; }
+        public void clear() { m.clear(); }
+        public K lower(K e) { return m.lowerKey(e); }
+        public K floor(K e) { return m.floorKey(e); }
+        public K ceiling(K e) { return m.ceilingKey(e); }
+        public K higher(K e) { return m.higherKey(e); }
+        public Comparator<? super K> comparator() { return m.comparator(); }
+        public K first() { return m.firstKey(); }
+        public K last() { return m.lastKey(); }
+        public K pollFirst() {
+            Map.Entry<K,V> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public K pollLast() {
+            Map.Entry<K,V> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public Iterator<K> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new KeyIterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException | NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+        public Iterator<K> descendingIterator() {
+            return descendingSet().iterator();
+        }
+        public NavigableSet<K> subSet(K fromElement,
+                                      boolean fromInclusive,
+                                      K toElement,
+                                      boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                         toElement,   toInclusive));
+        }
+        public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public NavigableSet<K> subSet(K fromElement, K toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public NavigableSet<K> headSet(K toElement) {
+            return headSet(toElement, false);
+        }
+        public NavigableSet<K> tailSet(K fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<K> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<K> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+    }
+
+    static final class Values<K,V> extends AbstractCollection<V> {
+        final ConcurrentNavigableMap<K,V> m;
+        Values(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<V> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsValue(o); }
+        public void clear() { m.clear(); }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<V> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).valueSpliterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeValueIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                V v = e.getValue();
+                if (filter.test(v) && m.remove(e.getKey(), v))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
+        final ConcurrentNavigableMap<K,V> m;
+        EntrySet(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new EntryIterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            V 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<?,?> e = (Map.Entry<?,?>)o;
+            return m.remove(e.getKey(),
+                            e.getValue());
+        }
+        public boolean isEmpty() {
+            return m.isEmpty();
+        }
+        public int size() {
+            return m.size();
+        }
+        public void clear() {
+            m.clear();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException | NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).entrySpliterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeEntryIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                if (filter.test(e) && m.remove(e.getKey(), e.getValue()))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Submaps returned by {@link ConcurrentSkipListMap} submap operations
+     * represent a subrange of mappings of their underlying maps.
+     * Instances of this class support all methods of their underlying
+     * maps, differing in that mappings outside their range are ignored,
+     * and attempts to add mappings outside their ranges result in {@link
+     * IllegalArgumentException}.  Instances of this class are constructed
+     * only using the {@code subMap}, {@code headMap}, and {@code tailMap}
+     * methods of their underlying maps.
+     *
+     * @serial include
+     */
+    static final class SubMap<K,V> extends AbstractMap<K,V>
+        implements ConcurrentNavigableMap<K,V>, Serializable {
+        private static final long serialVersionUID = -7647078645895051609L;
+
+        /** Underlying map */
+        final ConcurrentSkipListMap<K,V> m;
+        /** lower bound key, or null if from start */
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final K lo;
+        /** upper bound key, or null if to end */
+        @SuppressWarnings("serial") // Conditionally serializable
+        private final K hi;
+        /** inclusion flag for lo */
+        private final boolean loInclusive;
+        /** inclusion flag for hi */
+        private final boolean hiInclusive;
+        /** direction */
+        final boolean isDescending;
+
+        // Lazily initialized view holders
+        private transient KeySet<K,V> keySetView;
+        private transient Values<K,V> valuesView;
+        private transient EntrySet<K,V> entrySetView;
+
+        /**
+         * Creates a new submap, initializing all fields.
+         */
+        SubMap(ConcurrentSkipListMap<K,V> map,
+               K fromKey, boolean fromInclusive,
+               K toKey, boolean toInclusive,
+               boolean isDescending) {
+            Comparator<? super K> cmp = map.comparator;
+            if (fromKey != null && toKey != null &&
+                cpr(cmp, fromKey, toKey) > 0)
+                throw new IllegalArgumentException("inconsistent range");
+            this.m = map;
+            this.lo = fromKey;
+            this.hi = toKey;
+            this.loInclusive = fromInclusive;
+            this.hiInclusive = toInclusive;
+            this.isDescending = isDescending;
+        }
+
+        /* ----------------  Utilities -------------- */
+
+        boolean tooLow(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (lo != null && ((c = cpr(cmp, key, lo)) < 0 ||
+                                   (c == 0 && !loInclusive)));
+        }
+
+        boolean tooHigh(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (hi != null && ((c = cpr(cmp, key, hi)) > 0 ||
+                                   (c == 0 && !hiInclusive)));
+        }
+
+        boolean inBounds(Object key, Comparator<? super K> cmp) {
+            return !tooLow(key, cmp) && !tooHigh(key, cmp);
+        }
+
+        void checkKeyBounds(K key, Comparator<? super K> cmp) {
+            if (key == null)
+                throw new NullPointerException();
+            if (!inBounds(key, cmp))
+                throw new IllegalArgumentException("key out of range");
+        }
+
+        /**
+         * Returns true if node key is less than upper bound of range.
+         */
+        boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n,
+                            Comparator<? super K> cmp) {
+            if (n == null)
+                return false;
+            if (hi == null)
+                return true;
+            K k = n.key;
+            if (k == null) // pass by markers and headers
+                return true;
+            int c = cpr(cmp, k, hi);
+            return c < 0 || (c == 0 && hiInclusive);
+        }
+
+        /**
+         * Returns lowest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) {
+            if (lo == null)
+                return m.findFirst();
+            else if (loInclusive)
+                return m.findNear(lo, GT|EQ, cmp);
+            else
+                return m.findNear(lo, GT, cmp);
+        }
+
+        /**
+         * Returns highest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) {
+            if (hi == null)
+                return m.findLast();
+            else if (hiInclusive)
+                return m.findNear(hi, LT|EQ, cmp);
+            else
+                return m.findNear(hi, LT, cmp);
+        }
+
+        /**
+         * Returns lowest absolute key (ignoring directionality).
+         */
+        K lowestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+            if (isBeforeEnd(n, cmp))
+                return n.key;
+            else
+                throw new NoSuchElementException();
+        }
+
+        /**
+         * Returns highest absolute key (ignoring directionality).
+         */
+        K highestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+            if (n != null) {
+                K last = n.key;
+                if (inBounds(last, cmp))
+                    return last;
+            }
+            throw new NoSuchElementException();
+        }
+
+        Map.Entry<K,V> lowestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
+                    return null;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+        }
+
+        Map.Entry<K,V> highestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
+                    return null;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+        }
+
+        Map.Entry<K,V> removeLowest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = loNode(cmp)) == null)
+                    return null;
+                else if (!inBounds((k = n.key), cmp))
+                    return null;
+                else if ((v = m.doRemove(k, null)) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        Map.Entry<K,V> removeHighest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = hiNode(cmp)) == null)
+                    return null;
+                else if (!inBounds((k = n.key), cmp))
+                    return null;
+                else if ((v = m.doRemove(k, null)) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        /**
+         * Submap version of ConcurrentSkipListMap.findNearEntry.
+         */
+        Map.Entry<K,V> getNearEntry(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp))
+                return ((rel & LT) != 0) ? null : lowestEntry();
+            if (tooHigh(key, cmp))
+                return ((rel & LT) != 0) ? highestEntry() : null;
+            AbstractMap.SimpleImmutableEntry<K,V> e =
+                m.findNearEntry(key, rel, cmp);
+            if (e == null || !inBounds(e.getKey(), cmp))
+                return null;
+            else
+                return e;
+        }
+
+        // Almost the same as getNearEntry, except for keys
+        K getNearKey(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp)) {
+                if ((rel & LT) == 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                    if (isBeforeEnd(n, cmp))
+                        return n.key;
+                }
+                return null;
+            }
+            if (tooHigh(key, cmp)) {
+                if ((rel & LT) != 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                    if (n != null) {
+                        K last = n.key;
+                        if (inBounds(last, cmp))
+                            return last;
+                    }
+                }
+                return null;
+            }
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                if (n.val != null)
+                    return n.key;
+            }
+        }
+
+        /* ----------------  Map API methods -------------- */
+
+        public boolean containsKey(Object key) {
+            if (key == null) throw new NullPointerException();
+            return inBounds(key, m.comparator) && m.containsKey(key);
+        }
+
+        public V get(Object key) {
+            if (key == null) throw new NullPointerException();
+            return (!inBounds(key, m.comparator)) ? null : m.get(key);
+        }
+
+        public V put(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.put(key, value);
+        }
+
+        public V remove(Object key) {
+            return (!inBounds(key, m.comparator)) ? null : m.remove(key);
+        }
+
+        public int size() {
+            Comparator<? super K> cmp = m.comparator;
+            long count = 0;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.val != null)
+                    ++count;
+            }
+            return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
+        }
+
+        public boolean isEmpty() {
+            Comparator<? super K> cmp = m.comparator;
+            return !isBeforeEnd(loNode(cmp), cmp);
+        }
+
+        public boolean containsValue(Object value) {
+            if (value == null)
+                throw new NullPointerException();
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                V v = n.val;
+                if (v != null && value.equals(v))
+                    return true;
+            }
+            return false;
+        }
+
+        public void clear() {
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.val != null)
+                    m.remove(n.key);
+            }
+        }
+
+        /* ----------------  ConcurrentMap API methods -------------- */
+
+        public V putIfAbsent(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.putIfAbsent(key, value);
+        }
+
+        public boolean remove(Object key, Object value) {
+            return inBounds(key, m.comparator) && m.remove(key, value);
+        }
+
+        public boolean replace(K key, V oldValue, V newValue) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        public V replace(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, value);
+        }
+
+        /* ----------------  SortedMap API methods -------------- */
+
+        public Comparator<? super K> comparator() {
+            Comparator<? super K> cmp = m.comparator();
+            if (isDescending)
+                return Collections.reverseOrder(cmp);
+            else
+                return cmp;
+        }
+
+        /**
+         * Utility to create submaps, where given bounds override
+         * unbounded(null) ones and/or are checked against bounded ones.
+         */
+        SubMap<K,V> newSubMap(K fromKey, boolean fromInclusive,
+                              K toKey, boolean toInclusive) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // flip senses
+                K tk = fromKey;
+                fromKey = toKey;
+                toKey = tk;
+                boolean ti = fromInclusive;
+                fromInclusive = toInclusive;
+                toInclusive = ti;
+            }
+            if (lo != null) {
+                if (fromKey == null) {
+                    fromKey = lo;
+                    fromInclusive = loInclusive;
+                }
+                else {
+                    int c = cpr(cmp, fromKey, lo);
+                    if (c < 0 || (c == 0 && !loInclusive && fromInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            if (hi != null) {
+                if (toKey == null) {
+                    toKey = hi;
+                    toInclusive = hiInclusive;
+                }
+                else {
+                    int c = cpr(cmp, toKey, hi);
+                    if (c > 0 || (c == 0 && !hiInclusive && toInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            return new SubMap<K,V>(m, fromKey, fromInclusive,
+                                   toKey, toInclusive, isDescending);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                  K toKey, boolean toInclusive) {
+            if (fromKey == null || toKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, fromInclusive, toKey, toInclusive);
+        }
+
+        public SubMap<K,V> headMap(K toKey, boolean inclusive) {
+            if (toKey == null)
+                throw new NullPointerException();
+            return newSubMap(null, false, toKey, inclusive);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            if (fromKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, inclusive, null, false);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public SubMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        public SubMap<K,V> descendingMap() {
+            return new SubMap<K,V>(m, lo, loInclusive,
+                                   hi, hiInclusive, !isDescending);
+        }
+
+        /* ----------------  Relational methods -------------- */
+
+        public Map.Entry<K,V> ceilingEntry(K key) {
+            return getNearEntry(key, GT|EQ);
+        }
+
+        public K ceilingKey(K key) {
+            return getNearKey(key, GT|EQ);
+        }
+
+        public Map.Entry<K,V> lowerEntry(K key) {
+            return getNearEntry(key, LT);
+        }
+
+        public K lowerKey(K key) {
+            return getNearKey(key, LT);
+        }
+
+        public Map.Entry<K,V> floorEntry(K key) {
+            return getNearEntry(key, LT|EQ);
+        }
+
+        public K floorKey(K key) {
+            return getNearKey(key, LT|EQ);
+        }
+
+        public Map.Entry<K,V> higherEntry(K key) {
+            return getNearEntry(key, GT);
+        }
+
+        public K higherKey(K key) {
+            return getNearKey(key, GT);
+        }
+
+        public K firstKey() {
+            return isDescending ? highestKey() : lowestKey();
+        }
+
+        public K lastKey() {
+            return isDescending ? lowestKey() : highestKey();
+        }
+
+        public Map.Entry<K,V> firstEntry() {
+            return isDescending ? highestEntry() : lowestEntry();
+        }
+
+        public Map.Entry<K,V> lastEntry() {
+            return isDescending ? lowestEntry() : highestEntry();
+        }
+
+        public Map.Entry<K,V> pollFirstEntry() {
+            return isDescending ? removeHighest() : removeLowest();
+        }
+
+        public Map.Entry<K,V> pollLastEntry() {
+            return isDescending ? removeLowest() : removeHighest();
+        }
+
+        /* ---------------- Submap Views -------------- */
+
+        public NavigableSet<K> keySet() {
+            KeySet<K,V> ks;
+            if ((ks = keySetView) != null) return ks;
+            return keySetView = new KeySet<>(this);
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            KeySet<K,V> ks;
+            if ((ks = keySetView) != null) return ks;
+            return keySetView = new KeySet<>(this);
+        }
+
+        public Collection<V> values() {
+            Values<K,V> vs;
+            if ((vs = valuesView) != null) return vs;
+            return valuesView = new Values<>(this);
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySet<K,V> es;
+            if ((es = entrySetView) != null) return es;
+            return entrySetView = new EntrySet<K,V>(this);
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        /**
+         * Variant of main Iter class to traverse through submaps.
+         * Also serves as back-up Spliterator for views.
+         */
+        abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
+            /** the last node returned by next() */
+            Node<K,V> lastReturned;
+            /** the next node to return from next(); */
+            Node<K,V> next;
+            /** Cache of next value field to maintain weak consistency */
+            V nextValue;
+
+            SubMapIter() {
+                VarHandle.acquireFence();
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = isDescending ? hiNode(cmp) : loNode(cmp);
+                    if (next == null)
+                        break;
+                    V x = next.val;
+                    if (x != null) {
+                        if (! inBounds(next.key, cmp))
+                            next = null;
+                        else
+                            nextValue = x;
+                        break;
+                    }
+                }
+            }
+
+            public final boolean hasNext() {
+                return next != null;
+            }
+
+            final void advance() {
+                if (next == null)
+                    throw new NoSuchElementException();
+                lastReturned = next;
+                if (isDescending)
+                    descend();
+                else
+                    ascend();
+            }
+
+            private void ascend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = next.next;
+                    if (next == null)
+                        break;
+                    V x = next.val;
+                    if (x != null) {
+                        if (tooHigh(next.key, cmp))
+                            next = null;
+                        else
+                            nextValue = x;
+                        break;
+                    }
+                }
+            }
+
+            private void descend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = m.findNear(lastReturned.key, LT, cmp);
+                    if (next == null)
+                        break;
+                    V x = next.val;
+                    if (x != null) {
+                        if (tooLow(next.key, cmp))
+                            next = null;
+                        else
+                            nextValue = x;
+                        break;
+                    }
+                }
+            }
+
+            public void remove() {
+                Node<K,V> l = lastReturned;
+                if (l == null)
+                    throw new IllegalStateException();
+                m.remove(l.key);
+                lastReturned = null;
+            }
+
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            public boolean tryAdvance(Consumer<? super T> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+
+            public void forEachRemaining(Consumer<? super T> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+        }
+
+        final class SubMapValueIterator extends SubMapIter<V> {
+            public V next() {
+                V v = nextValue;
+                advance();
+                return v;
+            }
+            public int characteristics() {
+                return 0;
+            }
+        }
+
+        final class SubMapKeyIterator extends SubMapIter<K> {
+            public K next() {
+                Node<K,V> n = next;
+                advance();
+                return n.key;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K> getComparator() {
+                return SubMap.this.comparator();
+            }
+        }
+
+        final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
+            public Map.Entry<K,V> next() {
+                Node<K,V> n = next;
+                V v = nextValue;
+                advance();
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT;
+            }
+        }
+    }
+
+    // default Map method overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null)
+                    action.accept(n.key, v);
+                b = n;
+            }
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                while ((v = n.val) != null) {
+                    V r = function.apply(n.key, v);
+                    if (r == null) throw new NullPointerException();
+                    if (VAL.compareAndSet(n, v, r))
+                        break;
+                }
+                b = n;
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySet.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    K k = n.key;
+                    Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                    if (function.test(e) && remove(k, v))
+                        removed = true;
+                }
+                b = n;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for Values.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && function.test(v) && remove(n.key, v))
+                    removed = true;
+                b = n;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Base class providing common structure for Spliterators.
+     * (Although not all that much common functionality; as usual for
+     * view classes, details annoyingly vary in key, value, and entry
+     * subclasses in ways that are not worth abstracting out for
+     * internal classes.)
+     *
+     * The basic split strategy is to recursively descend from top
+     * level, row by row, descending to next row when either split
+     * off, or the end of row is encountered. Control of the number of
+     * splits relies on some statistical estimation: The expected
+     * remaining number of elements of a skip list when advancing
+     * either across or down decreases by about 25%.
+     */
+    abstract static class CSLMSpliterator<K,V> {
+        final Comparator<? super K> comparator;
+        final K fence;     // exclusive upper bound for keys, or null if to end
+        Index<K,V> row;    // the level to split out
+        Node<K,V> current; // current traversal node; initialize at origin
+        long est;          // size estimate
+        CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                        Node<K,V> origin, K fence, long est) {
+            this.comparator = comparator; this.row = row;
+            this.current = origin; this.fence = fence; this.est = est;
+        }
+
+        public final long estimateSize() { return est; }
+    }
+
+    static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, long est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.val != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new KeySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if (e.val != null)
+                    action.accept(k);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if (e.val != null) {
+                    current = e.next;
+                    action.accept(k);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<? super K> getComparator() {
+            return comparator;
+        }
+    }
+    // factory method for KeySpliterator
+    final KeySpliterator<K,V> keySpliterator() {
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
+        }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new KeySpliterator<K,V>(comparator, h, n, null, est);
+    }
+
+    static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, long est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.val != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new ValueSpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; V v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.val) != null)
+                    action.accept(v);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; V v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.val) != null) {
+                    current = e.next;
+                    action.accept(v);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.ORDERED |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final ValueSpliterator<K,V> valueSpliterator() {
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
+        }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new ValueSpliterator<K,V>(comparator, h, n, null, est);
+    }
+
+    static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                         Node<K,V> origin, K fence, long est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.val != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new EntrySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; V v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.val) != null) {
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; V v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.val) != null) {
+                    current = e.next;
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<Map.Entry<K,V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (comparator != null) {
+                return Map.Entry.comparingByKey(comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K,V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final EntrySpliterator<K,V> entrySpliterator() {
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
+        }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new EntrySpliterator<K,V>(comparator, h, n, null, est);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle ADDER;
+    private static final VarHandle NEXT;
+    private static final VarHandle VAL;
+    private static final VarHandle RIGHT;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
+                                   Index.class);
+            ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
+                                    LongAdder.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            VAL = l.findVarHandle(Node.class, "val", Object.class);
+            RIGHT = l.findVarHandle(Index.class, "right", Index.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/ConcurrentSkipListSet.java b/android-35/java/util/concurrent/ConcurrentSkipListSet.java
new file mode 100644
index 0000000..0db76e0
--- /dev/null
+++ b/android-35/java/util/concurrent/ConcurrentSkipListSet.java
@@ -0,0 +1,550 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.reflect.Field;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Spliterator;
+
+/**
+ * A scalable concurrent {@link NavigableSet} implementation based on
+ * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
+ * sorted according to their {@linkplain Comparable natural ordering},
+ * or by a {@link Comparator} provided at set creation time, depending
+ * on which constructor is used.
+ *
+ * <p>This implementation provides expected average <i>log(n)</i> time
+ * cost for the {@code contains}, {@code add}, and {@code remove}
+ * operations and their variants.  Insertion, removal, and access
+ * operations safely execute concurrently by multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <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 sets, 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.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe 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}
+ * interfaces. Like most other concurrent collection implementations,
+ * this class does not permit the use of {@code null} elements,
+ * because {@code null} arguments and return values cannot be reliably
+ * distinguished from the absence of elements.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @author Doug Lea
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public class ConcurrentSkipListSet<E>
+    extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable {
+
+    private static final long serialVersionUID = -2479143111061671589L;
+
+    /**
+     * The underlying map. Uses Boolean.TRUE as value for each
+     * element.  This field is declared final for the sake of thread
+     * safety, which entails some ugliness in clone().
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    private final ConcurrentNavigableMap<E,Object> m;
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public ConcurrentSkipListSet() {
+        m = new ConcurrentSkipListMap<E,Object>();
+    }
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * the specified comparator.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public ConcurrentSkipListSet(Comparator<? super E> comparator) {
+        m = new ConcurrentSkipListMap<E,Object>(comparator);
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection, that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param c The elements that will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(Collection<? extends E> c) {
+        m = new ConcurrentSkipListMap<E,Object>();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new set containing the same elements and using the
+     * same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(SortedSet<E> s) {
+        m = new ConcurrentSkipListMap<E,Object>(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * For use by submaps
+     */
+    ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListSet}
+     * instance. (The elements themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    public ConcurrentSkipListSet<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListSet<E> clone =
+                (ConcurrentSkipListSet<E>) super.clone();
+            clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /* ---------------- Set operations -------------- */
+
+    /**
+     * Returns the number of elements in this set.  If this set
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * 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 sets, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that {@code e.equals(e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the
+     *         specified element
+     * @throws ClassCastException if {@code e} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return m.putIfAbsent(e, Boolean.TRUE) == null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code o.equals(e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if {@code o} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return m.remove(o, Boolean.TRUE);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+
+    /* ---------------- AbstractSet Overrides -------------- */
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o the object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        // Override AbstractSet version to avoid calling size()
+        if (o == this)
+            return true;
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        try {
+            return containsAll(c) && c.containsAll(this);
+        } catch (ClassCastException | NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.  If the specified collection is also
+     * a set, this operation effectively modifies this set so that its
+     * value is the <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean removeAll(Collection<?> c) {
+        // Override AbstractSet version to avoid unnecessary call to size()
+        boolean modified = false;
+        for (Object e : c)
+            if (remove(e))
+                modified = true;
+        return modified;
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    public E pollFirst() {
+        Map.Entry<E,Object> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    public E pollLast() {
+        Map.Entry<E,Object> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+
+    /* ---------------- SortedSet operations -------------- */
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public void addFirst(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}. The encounter order induced by this
+     * set's comparison method determines the position of elements, so explicit positioning
+     * is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     * @since 21
+     */
+    public void addLast(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement,
+                                  boolean fromInclusive,
+                                  E toElement,
+                                  boolean toInclusive) {
+        return new ConcurrentSkipListSet<E>
+            (m.subMap(fromElement, fromInclusive,
+                      toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    public NavigableSet<E> descendingSet() {
+        return new ConcurrentSkipListSet<E>(m.descendingMap());
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
+     * encounter order that is ascending order.  Overriding implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
+     * is {@code null} if the {@linkplain #comparator() set's comparator}
+     * is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return (m instanceof ConcurrentSkipListMap)
+            ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
+            : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
+    }
+
+    /** Initializes map field; for use in clone. */
+    private void setMap(ConcurrentNavigableMap<E,Object> map) {
+        @SuppressWarnings("removal")
+        Field mapField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = ConcurrentSkipListSet.class
+                        .getDeclaredField("m");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
+        try {
+            mapField.set(this, map);
+        } catch (IllegalAccessException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/CopyOnWriteArrayList.java b/android-35/java/util/concurrent/CopyOnWriteArrayList.java
new file mode 100644
index 0000000..4c83326
--- /dev/null
+++ b/android-35/java/util/concurrent/CopyOnWriteArrayList.java
@@ -0,0 +1,2106 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group.  Adapted and released, under explicit permission,
+ * from JDK ArrayList.java which carries the following copyright:
+ *
+ * Copyright 1997 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
+
+// Android-changed: Removed javadoc link to collections framework docs
+/**
+ * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
+ * operations ({@code add}, {@code set}, and so on) are implemented by
+ * making a fresh copy of the underlying array.
+ *
+ * <p>This is ordinarily too costly, but may be <em>more</em> efficient
+ * than alternatives when traversal operations vastly outnumber
+ * mutations, and is useful when you cannot or don't want to
+ * synchronize traversals, yet need to preclude interference among
+ * concurrent threads.  The "snapshot" style iterator method uses a
+ * reference to the state of the array at the point that the iterator
+ * was created. This array never changes during the lifetime of the
+ * iterator, so interference is impossible and the iterator is
+ * guaranteed not to throw {@code ConcurrentModificationException}.
+ * The iterator will not reflect additions, removals, or changes to
+ * the list since the iterator was created.  Element-changing
+ * operations on iterators themselves ({@code remove}, {@code set}, and
+ * {@code add}) are not supported. These methods throw
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>All elements are permitted, including {@code null}.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code CopyOnWriteArrayList}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code CopyOnWriteArrayList} in another thread.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this list
+ */
+public class CopyOnWriteArrayList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
+    private static final long serialVersionUID = 8673264195747942595L;
+
+    /**
+     * The lock protecting all mutators.  (We have a mild preference
+     * for builtin monitors over ReentrantLock when either will do.)
+     */
+    final transient Object lock = new Object();
+
+    /** The array, accessed only via getArray/setArray. */
+    private transient volatile Object[] array;
+
+    /**
+     * Gets the array.  Non-private so as to also be accessible
+     * from CopyOnWriteArraySet class.
+     */
+    final Object[] getArray() {
+        return array;
+    }
+
+    /**
+     * Sets the array.
+     */
+    final void setArray(Object[] a) {
+        array = a;
+    }
+
+    /**
+     * Creates an empty list.
+     */
+    public CopyOnWriteArrayList() {
+        setArray(new Object[0]);
+    }
+
+    /**
+     * Creates a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection of initially held elements
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArrayList(Collection<? extends E> c) {
+        Object[] es;
+        if (c.getClass() == CopyOnWriteArrayList.class)
+            es = ((CopyOnWriteArrayList<?>)c).getArray();
+        else {
+            es = c.toArray();
+            // Android-changed: Defend against c.toArray (incorrectly) not returning Object[]
+            //                  (see b/204397945)
+            // if (c.getClass() != java.util.ArrayList.class)
+            if (es.getClass() != Object[].class)
+                es = Arrays.copyOf(es, es.length, Object[].class);
+        }
+        setArray(es);
+    }
+
+    /**
+     * Creates a list holding a copy of the given array.
+     *
+     * @param toCopyIn the array (a copy of this array is used as the
+     *        internal array)
+     * @throws NullPointerException if the specified array is null
+     */
+    public CopyOnWriteArrayList(E[] toCopyIn) {
+        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return getArray().length;
+    }
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * static version of indexOf, to allow repeated calls without
+     * needing to re-acquire array each time.
+     * @param o element to search for
+     * @param es the array
+     * @param from first index to search
+     * @param to one past last index to search
+     * @return index of element, or -1 if absent
+     */
+    private static int indexOfRange(Object o, Object[] es, int from, int to) {
+        if (o == null) {
+            for (int i = from; i < to; i++)
+                if (es[i] == null)
+                    return i;
+        } else {
+            for (int i = from; i < to; i++)
+                if (o.equals(es[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * static version of lastIndexOf.
+     * @param o element to search for
+     * @param es the array
+     * @param from index of first element of range, last element to search
+     * @param to one past last element of range, first element to search
+     * @return index of element, or -1 if absent
+     */
+    private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
+        if (o == null) {
+            for (int i = to - 1; i >= from; i--)
+                if (es[i] == null)
+                    return i;
+        } else {
+            for (int i = to - 1; i >= from; i--)
+                if (o.equals(es[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        Object[] es = getArray();
+        return indexOfRange(o, es, 0, es.length);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this list, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code i >= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this list at position {@code index} or later in the list;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public int indexOf(E e, int index) {
+        Object[] es = getArray();
+        return indexOfRange(e, es, index, es.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        Object[] es = getArray();
+        return lastIndexOfRange(o, es, 0, es.length);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this list, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * {@code i <= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this list;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this list
+     */
+    public int lastIndexOf(E e, int index) {
+        Object[] es = getArray();
+        return lastIndexOfRange(e, es, 0, index + 1);
+    }
+
+    /**
+     * Returns a shallow copy of this list.  (The elements themselves
+     * are not copied.)
+     *
+     * @return a clone of this list
+     */
+    public Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            CopyOnWriteArrayList<E> clone =
+                (CopyOnWriteArrayList<E>) super.clone();
+            clone.resetLock();
+            // Unlike in readObject, here we cannot visibility-piggyback on the
+            // volatile write in setArray().
+            VarHandle.releaseFence();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this list
+     */
+    public Object[] toArray() {
+        return getArray().clone();
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If this list fits in the specified array with room to spare
+     * (i.e., the array has more elements than this list), the element in
+     * the array immediately following the end of the list is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * list <i>only</i> if the caller knows that this list does not contain
+     * any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        Object[] es = getArray();
+        int len = es.length;
+        if (a.length < len)
+            return (T[]) Arrays.copyOf(es, len, a.getClass());
+        else {
+            System.arraycopy(es, 0, a, 0, len);
+            if (a.length > len)
+                a[len] = null;
+            return a;
+        }
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] a, int index) {
+        return (E) a[index];
+    }
+
+    static String outOfBounds(int index, int size) {
+        return "Index: " + index + ", Size: " + size;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        return elementAt(getArray(), index);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getFirst() {
+        Object[] es = getArray();
+        if (es.length == 0)
+            throw new NoSuchElementException();
+        else
+            return elementAt(es, 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E getLast() {
+        Object[] es = getArray();
+        if (es.length == 0)
+            throw new NoSuchElementException();
+        else
+            return elementAt(es, es.length - 1);
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            E oldValue = elementAt(es, index);
+
+            if (oldValue != element) {
+                es = es.clone();
+                es[index] = element;
+            }
+            // Ensure volatile write semantics even when oldvalue == element
+            setArray(es);
+            return oldValue;
+        }
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            es = Arrays.copyOf(es, len + 1);
+            es[len] = e;
+            setArray(es);
+            return true;
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            Object[] newElements;
+            int numMoved = len - index;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(es, len + 1);
+            else {
+                newElements = new Object[len + 1];
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index, newElements, index + 1,
+                                 numMoved);
+            }
+            newElements[index] = element;
+            setArray(newElements);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 21
+     */
+    public void addFirst(E e) {
+        add(0, e);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 21
+     */
+    public void addLast(E e) {
+        synchronized (lock) {
+            add(getArray().length, e);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the list.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            E oldValue = elementAt(es, index);
+            int numMoved = len - index - 1;
+            Object[] newElements;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(es, len - 1);
+            else {
+                newElements = new Object[len - 1];
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index + 1, newElements, index,
+                                 numMoved);
+            }
+            setArray(newElements);
+            return oldValue;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeFirst() {
+        synchronized (lock) {
+            if (getArray().length == 0)
+                throw new NoSuchElementException();
+            else
+                return remove(0);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NoSuchElementException {@inheritDoc}
+     * @since 21
+     */
+    public E removeLast() {
+        synchronized (lock) {
+            int size = getArray().length;
+            if (size == 0)
+                throw new NoSuchElementException();
+            else
+                return remove(size - 1);
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If this list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * {@code i} such that {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        Object[] snapshot = getArray();
+        int index = indexOfRange(o, snapshot, 0, snapshot.length);
+        return index >= 0 && remove(o, snapshot, index);
+    }
+
+    /**
+     * A version of remove(Object) using the strong hint that given
+     * recent snapshot contains o at the given index.
+     */
+    private boolean remove(Object o, Object[] snapshot, int index) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) findIndex: {
+                int prefix = Math.min(index, len);
+                for (int i = 0; i < prefix; i++) {
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(o, current[i])) {
+                        index = i;
+                        break findIndex;
+                    }
+                }
+                if (index >= len)
+                    return false;
+                if (current[index] == o)
+                    break findIndex;
+                index = indexOfRange(o, current, index, len);
+                if (index < 0)
+                    return false;
+            }
+            Object[] newElements = new Object[len - 1];
+            System.arraycopy(current, 0, newElements, 0, index);
+            System.arraycopy(current, index + 1,
+                             newElements, index,
+                             len - index - 1);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range
+     *         ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
+     */
+    void removeRange(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+
+            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
+                throw new IndexOutOfBoundsException();
+            int newlen = len - (toIndex - fromIndex);
+            int numMoved = len - toIndex;
+            if (numMoved == 0)
+                setArray(Arrays.copyOf(es, newlen));
+            else {
+                Object[] newElements = new Object[newlen];
+                System.arraycopy(es, 0, newElements, 0, fromIndex);
+                System.arraycopy(es, toIndex, newElements,
+                                 fromIndex, numMoved);
+                setArray(newElements);
+            }
+        }
+    }
+
+    /**
+     * Appends the element, if not present.
+     *
+     * @param e element to be added to this list, if absent
+     * @return {@code true} if the element was added
+     */
+    public boolean addIfAbsent(E e) {
+        Object[] snapshot = getArray();
+        return indexOfRange(e, snapshot, 0, snapshot.length) < 0
+            && addIfAbsent(e, snapshot);
+    }
+
+    /**
+     * A version of addIfAbsent using the strong hint that given
+     * recent snapshot does not contain e.
+     */
+    private boolean addIfAbsent(E e, Object[] snapshot) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) {
+                // Optimize for lost race to another addXXX operation
+                int common = Math.min(snapshot.length, len);
+                for (int i = 0; i < common; i++)
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(e, current[i]))
+                        return false;
+                if (indexOfRange(e, current, common, len) >= 0)
+                        return false;
+            }
+            Object[] newElements = Arrays.copyOf(current, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        Object[] es = getArray();
+        int len = es.length;
+        for (Object e : c) {
+            if (indexOfRange(e, es, 0, len) < 0)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in
+     * the specified collection. This is a particularly expensive operation
+     * in this class because of the need for an internal temporary array.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all of
+     * its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /**
+     * Appends all of the elements in the specified collection that
+     * are not already contained in this list, to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return the number of elements added
+     * @throws NullPointerException if the specified collection is null
+     * @see #addIfAbsent(Object)
+     */
+    public int addAllAbsent(Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        if (c.getClass() != ArrayList.class) {
+            cs = cs.clone();
+        }
+        if (cs.length == 0)
+            return 0;
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            int added = 0;
+            // uniquify and compact elements in cs
+            for (int i = 0; i < cs.length; ++i) {
+                Object e = cs[i];
+                if (indexOfRange(e, es, 0, len) < 0 &&
+                    indexOfRange(e, cs, 0, added) < 0)
+                    cs[added++] = e;
+            }
+            if (added > 0) {
+                Object[] newElements = Arrays.copyOf(es, len + added);
+                System.arraycopy(cs, 0, newElements, len, added);
+                setArray(newElements);
+            }
+            return added;
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
+     */
+    public void clear() {
+        synchronized (lock) {
+            setArray(new Object[0]);
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end
+     * of this list, in the order that they are returned by the specified
+     * collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
+            ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
+        if (cs.length == 0)
+            return false;
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            Object[] newElements;
+            if (len == 0 && (c.getClass() == CopyOnWriteArrayList.class ||
+                             c.getClass() == ArrayList.class)) {
+                newElements = cs;
+            } else {
+                newElements = Arrays.copyOf(es, len + cs.length);
+                System.arraycopy(cs, 0, newElements, len, cs.length);
+            }
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in this list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element
+     *        from the specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(int,Object)
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            if (cs.length == 0)
+                return false;
+            int numMoved = len - index;
+            Object[] newElements;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(es, len + cs.length);
+            else {
+                newElements = new Object[len + cs.length];
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index,
+                                 newElements, index + cs.length,
+                                 numMoved);
+            }
+            System.arraycopy(cs, 0, newElements, index, cs.length);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        for (Object x : getArray()) {
+            @SuppressWarnings("unchecked") E e = (E) x;
+            action.accept(e);
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        synchronized (lock) {
+            return bulkRemove(filter, 0, getArray().length);
+        }
+    }
+
+    boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray();
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            int deleted = 1;
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i))) {
+                    setBit(deathRow, i - beg);
+                    deleted++;
+                }
+            // Did filter reentrantly modify the list?
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    newElts[w++] = es[i];
+            System.arraycopy(es, i, newElts, w, es.length - i);
+            setArray(newElts);
+            return true;
+        } else {
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            return false;
+        }
+    }
+
+    public void replaceAll(UnaryOperator<E> operator) {
+        synchronized (lock) {
+            replaceAllRange(operator, 0, getArray().length);
+        }
+    }
+
+    void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        Objects.requireNonNull(operator);
+        final Object[] es = getArray().clone();
+        for (; i < end; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        setArray(es);
+    }
+
+    public void sort(Comparator<? super E> c) {
+        synchronized (lock) {
+            sortRange(c, 0, getArray().length);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    void sortRange(Comparator<? super E> c, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        Arrays.sort(es, i, end, (Comparator<Object>)c);
+        setArray(es);
+    }
+
+    /**
+     * Saves this list to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The length of the array backing the list is emitted
+     *               (int), followed by all of its elements (each an Object)
+     *               in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        s.defaultWriteObject();
+
+        Object[] es = getArray();
+        // Write out array length
+        s.writeInt(es.length);
+
+        // Write out all elements in the proper order.
+        for (Object element : es)
+            s.writeObject(element);
+    }
+
+    /**
+     * Reconstitutes this list from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        s.defaultReadObject();
+
+        // bind to new lock
+        resetLock();
+
+        // Read in array length and allocate array
+        int len = s.readInt();
+        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
+        Object[] es = new Object[len];
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < len; i++)
+            es[i] = s.readObject();
+        setArray(es);
+    }
+
+    /**
+     * Returns a string representation of this list.  The string
+     * representation consists of the string representations of the list's
+     * elements in the order they are returned by its iterator, enclosed in
+     * square brackets ({@code "[]"}).  Adjacent elements are separated by
+     * the characters {@code ", "} (comma and space).  Elements are
+     * converted to strings as by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this list
+     */
+    public String toString() {
+        return Arrays.toString(getArray());
+    }
+
+    /**
+     * Compares the specified object with this list for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link List} and the sequence
+     * of elements returned by an {@linkplain List#iterator() iterator}
+     * over the specified list is the same as the sequence returned by
+     * an iterator over this list.  The two sequences are considered to
+     * be the same if they have the same length and corresponding
+     * elements at the same position in the sequence are <em>equal</em>.
+     * Two elements {@code e1} and {@code e2} are considered
+     * <em>equal</em> if {@code Objects.equals(e1, e2)}.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        List<?> list = (List<?>)o;
+        Iterator<?> it = list.iterator();
+        for (Object element : getArray())
+            if (!it.hasNext() || !Objects.equals(element, it.next()))
+                return false;
+        return !it.hasNext();
+    }
+
+    private static int hashCodeOfRange(Object[] es, int from, int to) {
+        int hashCode = 1;
+        for (int i = from; i < to; i++) {
+            Object x = es[i];
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        }
+        return hashCode;
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * <p>This implementation uses the definition in {@link List#hashCode}.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        Object[] es = getArray();
+        return hashCodeOfRange(es, 0, es.length);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     */
+    public ListIterator<E> listIterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        Object[] es = getArray();
+        int len = es.length;
+        if (index < 0 || index > len)
+            throw new IndexOutOfBoundsException(outOfBounds(index, len));
+
+        return new COWIterator<E>(es, index);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#ORDERED}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the list
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
+    }
+
+    static final class COWIterator<E> implements ListIterator<E> {
+        /** Snapshot of the array */
+        private final Object[] snapshot;
+        /** Index of element to be returned by subsequent call to next.  */
+        private int cursor;
+
+        COWIterator(Object[] es, int initialCursor) {
+            cursor = initialCursor;
+            snapshot = es;
+        }
+
+        public boolean hasNext() {
+            return cursor < snapshot.length;
+        }
+
+        public boolean hasPrevious() {
+            return cursor > 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (! hasNext())
+                throw new NoSuchElementException();
+            return (E) snapshot[cursor++];
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            if (! hasPrevious())
+                throw new NoSuchElementException();
+            return (E) snapshot[--cursor];
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code remove}
+         *         is not supported by this iterator.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code set}
+         *         is not supported by this iterator.
+         */
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code add}
+         *         is not supported by this iterator.
+         */
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int size = snapshot.length;
+            int i = cursor;
+            cursor = size;
+            for (; i < size; i++)
+                action.accept(elementAt(snapshot, i));
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * The returned list is backed by this list, so changes in the
+     * returned list are reflected in this list.
+     *
+     * <p>The semantics of the list returned by this method become
+     * undefined if the backing list (i.e., this list) is modified in
+     * any way other than via the returned list.
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] es = getArray();
+            int len = es.length;
+            int size = toIndex - fromIndex;
+            if (fromIndex < 0 || toIndex > len || size < 0)
+                throw new IndexOutOfBoundsException();
+            return new COWSubList(es, fromIndex, size);
+        }
+    }
+
+    /**
+     * Sublist for CopyOnWriteArrayList.
+     */
+    private class COWSubList implements List<E>, RandomAccess {
+        private final int offset;
+        private int size;
+        private Object[] expectedArray;
+
+        COWSubList(Object[] es, int offset, int size) {
+            // assert Thread.holdsLock(lock);
+            expectedArray = es;
+            this.offset = offset;
+            this.size = size;
+        }
+
+        private void checkForComodification() {
+            // assert Thread.holdsLock(lock);
+            if (getArray() != expectedArray)
+                throw new ConcurrentModificationException();
+        }
+
+        private Object[] getArrayChecked() {
+            // assert Thread.holdsLock(lock);
+            Object[] a = getArray();
+            if (a != expectedArray)
+                throw new ConcurrentModificationException();
+            return a;
+        }
+
+        private void rangeCheck(int index) {
+            // assert Thread.holdsLock(lock);
+            if (index < 0 || index >= size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        private void rangeCheckForAdd(int index) {
+            // assert Thread.holdsLock(lock);
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        public Object[] toArray() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return Arrays.copyOfRange(es, offset, offset + size);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            if (a.length < size)
+                return (T[]) Arrays.copyOfRange(
+                        es, offset, offset + size, a.getClass());
+            else {
+                System.arraycopy(es, offset, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            }
+        }
+
+        public int indexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = indexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public int lastIndexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = lastIndexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        public boolean containsAll(Collection<?> c) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            for (Object o : c)
+                if (indexOfRange(o, es, offset, offset + size) < 0)
+                    return false;
+            return true;
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public String toString() {
+            return Arrays.toString(toArray());
+        }
+
+        public int hashCode() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return hashCodeOfRange(es, offset, offset + size);
+        }
+
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof List))
+                return false;
+            Iterator<?> it = ((List<?>)o).iterator();
+
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+
+            for (int i = offset, end = offset + size; i < end; i++)
+                if (!it.hasNext() || !Objects.equals(es[i], it.next()))
+                    return false;
+            return !it.hasNext();
+        }
+
+        public E set(int index, E element) {
+            synchronized (lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E x = CopyOnWriteArrayList.this.set(offset + index, element);
+                expectedArray = getArray();
+                return x;
+            }
+        }
+
+        public E get(int index) {
+            synchronized (lock) {
+                rangeCheck(index);
+                checkForComodification();
+                return CopyOnWriteArrayList.this.get(offset + index);
+            }
+        }
+
+        public E getFirst() {
+            synchronized (lock) {
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return get(0);
+            }
+        }
+
+        public E getLast() {
+            synchronized (lock) {
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return get(size - 1);
+            }
+        }
+
+        public int size() {
+            synchronized (lock) {
+                checkForComodification();
+                return size;
+            }
+        }
+
+        public boolean add(E element) {
+            synchronized (lock) {
+                checkForComodification();
+                CopyOnWriteArrayList.this.add(offset + size, element);
+                expectedArray = getArray();
+                size++;
+            }
+            return true;
+        }
+
+        public void add(int index, E element) {
+            synchronized (lock) {
+                checkForComodification();
+                rangeCheckForAdd(index);
+                CopyOnWriteArrayList.this.add(offset + index, element);
+                expectedArray = getArray();
+                size++;
+            }
+        }
+
+        public void addFirst(E e) {
+            add(0, e);
+        }
+
+        public void addLast(E e) {
+            synchronized (lock) {
+                add(size, e);
+            }
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            synchronized (lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + size, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (lock) {
+                rangeCheckForAdd(index);
+                final Object[] oldArray = getArrayChecked();
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + index, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
+        public void clear() {
+            synchronized (lock) {
+                checkForComodification();
+                removeRange(offset, offset + size);
+                expectedArray = getArray();
+                size = 0;
+            }
+        }
+
+        public E remove(int index) {
+            synchronized (lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E result = CopyOnWriteArrayList.this.remove(offset + index);
+                expectedArray = getArray();
+                size--;
+                return result;
+            }
+        }
+
+        public E removeFirst() {
+            synchronized (lock) {
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return remove(0);
+            }
+        }
+
+        public E removeLast() {
+            synchronized (lock) {
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return remove(size - 1);
+            }
+        }
+
+        public boolean remove(Object o) {
+            synchronized (lock) {
+                checkForComodification();
+                int index = indexOf(o);
+                if (index == -1)
+                    return false;
+                remove(index);
+                return true;
+            }
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator(0);
+        }
+
+        public ListIterator<E> listIterator() {
+            return listIterator(0);
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            synchronized (lock) {
+                checkForComodification();
+                rangeCheckForAdd(index);
+                return new COWSubListIterator<E>(
+                    CopyOnWriteArrayList.this, index, offset, size);
+            }
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (lock) {
+                checkForComodification();
+                if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
+                    throw new IndexOutOfBoundsException();
+                return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
+            }
+        }
+
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int i, end; final Object[] es;
+            synchronized (lock) {
+                es = getArrayChecked();
+                i = offset;
+                end = i + size;
+            }
+            for (; i < end; i++)
+                action.accept(elementAt(es, i));
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            synchronized (lock) {
+                checkForComodification();
+                replaceAllRange(operator, offset, offset + size);
+                expectedArray = getArray();
+            }
+        }
+
+        public void sort(Comparator<? super E> c) {
+            synchronized (lock) {
+                checkForComodification();
+                sortRange(c, offset, offset + size);
+                expectedArray = getArray();
+            }
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> c.contains(e));
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> !c.contains(e));
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return bulkRemove(filter);
+        }
+
+        private boolean bulkRemove(Predicate<? super E> filter) {
+            synchronized (lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = CopyOnWriteArrayList.this.bulkRemove(
+                    filter, offset, offset + size);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
+        public Spliterator<E> spliterator() {
+            synchronized (lock) {
+                return Spliterators.spliterator(
+                        getArrayChecked(), offset, offset + size,
+                        Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            }
+        }
+
+        public List<E> reversed() {
+            return new Reversed<>(this, lock);
+        }
+    }
+
+    private static class COWSubListIterator<E> implements ListIterator<E> {
+        private final ListIterator<E> it;
+        private final int offset;
+        private final int size;
+
+        COWSubListIterator(List<E> l, int index, int offset, int size) {
+            this.offset = offset;
+            this.size = size;
+            it = l.listIterator(index + offset);
+        }
+
+        public boolean hasNext() {
+            return nextIndex() < size;
+        }
+
+        public E next() {
+            if (hasNext())
+                return it.next();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public boolean hasPrevious() {
+            return previousIndex() >= 0;
+        }
+
+        public E previous() {
+            if (hasPrevious())
+                return it.previous();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public int nextIndex() {
+            return it.nextIndex() - offset;
+        }
+
+        public int previousIndex() {
+            return it.previousIndex() - offset;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (hasNext()) {
+                action.accept(it.next());
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Modifications to the reversed view are permitted and will be propagated
+     * to this list. In addition, modifications to this list will be visible
+     * in the reversed view. Sublists and iterators of the reversed view have
+     * the same restrictions as those of this list.
+     *
+     * @since 21
+     */
+    public List<E> reversed() {
+        return new Reversed<>(this, lock);
+    }
+
+    /**
+     * Reversed view for CopyOnWriteArrayList and its sublists.
+     */
+    private static class Reversed<E> implements List<E>, RandomAccess {
+        final List<E> base;
+        final Object lock;
+
+        Reversed(List<E> base, Object lock) {
+            this.base = base;
+            this.lock = lock;
+        }
+
+        class DescendingIterator implements Iterator<E> {
+            final ListIterator<E> it;
+            DescendingIterator() {
+                synchronized (lock) {
+                    it = base.listIterator(base.size());
+                }
+            }
+            public boolean hasNext() { return it.hasPrevious(); }
+            public E next() { return it.previous(); }
+            public void remove() { it.remove(); }
+        }
+
+        class DescendingListIterator implements ListIterator<E> {
+            final ListIterator<E> it;
+            final int size; // iterator holds a snapshot of the array so this is constant
+
+            DescendingListIterator(int pos) {
+                synchronized (lock) {
+                    size = base.size();
+                    if (pos < 0 || pos > size)
+                        throw new IndexOutOfBoundsException();
+                    it = base.listIterator(size - pos);
+                }
+            }
+
+            public boolean hasNext() {
+                return it.hasPrevious();
+            }
+
+            public E next() {
+                return it.previous();
+            }
+
+            public boolean hasPrevious() {
+                return it.hasNext();
+            }
+
+            public E previous() {
+                return it.next();
+            }
+
+            public int nextIndex() {
+                return size - it.nextIndex();
+            }
+
+            public int previousIndex() {
+                return nextIndex() - 1;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public void set(E e) {
+                throw new UnsupportedOperationException();
+            }
+
+            public void add(E e) {
+                throw new UnsupportedOperationException();
+            }
+        }
+
+        // ========== Iterable ==========
+
+        public void forEach(Consumer<? super E> action) {
+            for (E e : this)
+                action.accept(e);
+        }
+
+        public Iterator<E> iterator() {
+            return new DescendingIterator();
+        }
+
+        public Spliterator<E> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+
+        // ========== Collection ==========
+
+        public boolean add(E e) {
+            base.add(0, e);
+            return true;
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            @SuppressWarnings("unchecked")
+            E[] es = (E[]) c.toArray();
+            if (es.length > 0) {
+                ArraysSupport.reverse(es);
+                base.addAll(0, Arrays.asList(es));
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public void clear() {
+            base.clear();
+        }
+
+        public boolean contains(Object o) {
+            return base.contains(o);
+        }
+
+        public boolean containsAll(Collection<?> c) {
+            return base.containsAll(c);
+        }
+
+        // copied from AbstractList
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof List))
+                return false;
+
+            ListIterator<E> e1 = listIterator();
+            ListIterator<?> e2 = ((List<?>) o).listIterator();
+            while (e1.hasNext() && e2.hasNext()) {
+                E o1 = e1.next();
+                Object o2 = e2.next();
+                if (!(o1==null ? o2==null : o1.equals(o2)))
+                    return false;
+            }
+            return !(e1.hasNext() || e2.hasNext());
+        }
+
+        // copied from AbstractList
+        public int hashCode() {
+            int hashCode = 1;
+            for (E e : this)
+                hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+            return hashCode;
+        }
+
+        public boolean isEmpty() {
+            return base.isEmpty();
+        }
+
+        public Stream<E> parallelStream() {
+            return StreamSupport.stream(spliterator(), true);
+        }
+
+        public boolean remove(Object o) {
+            synchronized (lock) {
+                int index = indexOf(o);
+                if (index == -1)
+                    return false;
+                remove(index);
+                return true;
+            }
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            return base.removeAll(c);
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            return base.retainAll(c);
+        }
+
+        public int size() {
+            return base.size();
+        }
+
+        public Stream<E> stream() {
+            return StreamSupport.stream(spliterator(), false);
+        }
+
+        public Object[] toArray() {
+            return ArraysSupport.reverse(base.toArray());
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            // TODO optimize this
+            return toArray(i -> (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), i));
+        }
+
+        public <T> T[] toArray(IntFunction<T[]> generator) {
+            return ArraysSupport.reverse(base.toArray(generator));
+        }
+
+        // copied from AbstractCollection
+        public String toString() {
+            Iterator<E> it = iterator();
+            if (! it.hasNext())
+                return "[]";
+
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            for (;;) {
+                E e = it.next();
+                sb.append(e == this ? "(this Collection)" : e);
+                if (! it.hasNext())
+                    return sb.append(']').toString();
+                sb.append(',').append(' ');
+            }
+        }
+
+        // ========== List ==========
+
+        public void add(int index, E element) {
+            synchronized (lock) {
+                base.add(base.size() - index, element);
+            }
+        }
+
+        public void addFirst(E e) {
+            base.add(e);
+        }
+
+        public void addLast(E e) {
+            base.add(0, e);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            @SuppressWarnings("unchecked")
+            E[] es = (E[]) c.toArray();
+            if (es.length > 0) {
+                ArraysSupport.reverse(es);
+                synchronized (lock) {
+                    base.addAll(base.size() - index, Arrays.asList(es));
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public E get(int i) {
+            synchronized (lock) {
+                return base.get(base.size() - i - 1);
+            }
+        }
+
+        public E getFirst() {
+            synchronized (lock) {
+                int size = base.size();
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return base.get(size - 1);
+            }
+        }
+
+        public E getLast() {
+            synchronized (lock) {
+                if (base.size() == 0)
+                    throw new NoSuchElementException();
+                else
+                    return base.get(0);
+            }
+        }
+
+        public int indexOf(Object o) {
+            synchronized (lock) {
+                int i = base.lastIndexOf(o);
+                return i == -1 ? -1 : base.size() - i - 1;
+            }
+        }
+
+        public int lastIndexOf(Object o) {
+            synchronized (lock) {
+                int i = base.indexOf(o);
+                return i == -1 ? -1 : base.size() - i - 1;
+            }
+        }
+
+        public ListIterator<E> listIterator() {
+            return new DescendingListIterator(0);
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            return new DescendingListIterator(index);
+        }
+
+        public E remove(int index) {
+            synchronized (lock) {
+                return base.remove(base.size() - index - 1);
+            }
+        }
+
+        public E removeFirst() {
+            synchronized (lock) {
+                int size = base.size();
+                if (size == 0)
+                    throw new NoSuchElementException();
+                else
+                    return base.remove(size - 1);
+            }
+        }
+
+        public E removeLast() {
+            synchronized (lock) {
+                if (base.size() == 0)
+                    throw new NoSuchElementException();
+                else
+                    return base.remove(0);
+            }
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            return base.removeIf(filter);
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            base.replaceAll(operator);
+        }
+
+        public void sort(Comparator<? super E> c) {
+            base.sort(Collections.reverseOrder(c));
+        }
+
+        public E set(int index, E element) {
+            synchronized (lock) {
+                return base.set(base.size() - index - 1, element);
+            }
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (lock) {
+                int size = base.size();
+                var sub = base.subList(size - toIndex, size - fromIndex);
+                return new Reversed<>(sub, lock);
+            }
+        }
+
+        public List<E> reversed() {
+            return base;
+        }
+    }
+
+    /** Initializes the lock; for use when deserializing or cloning. */
+    private void resetLock() {
+        @SuppressWarnings("removal")
+        Field lockField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = CopyOnWriteArrayList.class
+                        .getDeclaredField("lock");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
+        try {
+            lockField.set(this, new Object());
+        } catch (IllegalAccessException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/CopyOnWriteArraySet.java b/android-35/java/util/concurrent/CopyOnWriteArraySet.java
new file mode 100644
index 0000000..ab48a44
--- /dev/null
+++ b/android-35/java/util/concurrent/CopyOnWriteArraySet.java
@@ -0,0 +1,447 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * A {@link Set} that uses an internal {@link CopyOnWriteArrayList}
+ * for all of its operations.  Thus, it shares the same basic properties:
+ * <ul>
+ *  <li>It is best suited for applications in which set sizes generally
+ *       stay small, read-only operations
+ *       vastly outnumber mutative operations, and you need
+ *       to prevent interference among threads during traversal.
+ *  <li>It is thread-safe.
+ *  <li>Mutative operations ({@code add}, {@code set}, {@code remove}, etc.)
+ *      are expensive since they usually entail copying the entire underlying
+ *      array.
+ *  <li>Iterators do not support the mutative {@code remove} operation.
+ *  <li>Traversal via iterators is fast and cannot encounter
+ *      interference from other threads. Iterators rely on
+ *      unchanging snapshots of the array at the time the iterators were
+ *      constructed.
+ * </ul>
+ *
+ * <p><b>Sample Usage.</b> The following code sketch uses a
+ * copy-on-write set to maintain a set of Handler objects that
+ * perform some action upon state updates.
+ *
+ * <pre> {@code
+ * class Handler { void handle() { ... } }
+ *
+ * class X {
+ *   private final CopyOnWriteArraySet<Handler> handlers
+ *     = new CopyOnWriteArraySet<>();
+ *   public void addHandler(Handler h) { handlers.add(h); }
+ *
+ *   private long internalState;
+ *   private synchronized void changeState() { internalState = ...; }
+ *
+ *   public void update() {
+ *     changeState();
+ *     for (Handler handler : handlers)
+ *       handler.handle();
+ *   }
+ * }}</pre>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @see CopyOnWriteArrayList
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this set
+ */
+public class CopyOnWriteArraySet<E> extends AbstractSet<E>
+        implements java.io.Serializable {
+    private static final long serialVersionUID = 5457747651344034263L;
+
+    private final CopyOnWriteArrayList<E> al;
+
+    /**
+     * Creates an empty set.
+     */
+    public CopyOnWriteArraySet() {
+        al = new CopyOnWriteArrayList<E>();
+    }
+
+    /**
+     * Creates a set containing all of the elements of the specified
+     * collection.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArraySet(Collection<? extends E> c) {
+        if (c.getClass() == CopyOnWriteArraySet.class) {
+            @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
+                (CopyOnWriteArraySet<E>)c;
+            al = new CopyOnWriteArrayList<E>(cc.al);
+        }
+        else {
+            al = new CopyOnWriteArrayList<E>();
+            al.addAllAbsent(c);
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return al.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return al.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return al.contains(o);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    public Object[] toArray() {
+        return al.toArray();
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        return al.toArray(a);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        al.clear();
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code Objects.equals(o, e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return al.remove(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     */
+    public boolean add(E e) {
+        return al.addIfAbsent(e);
+    }
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        return (c instanceof Set)
+            ? compareSets(al.getArray(), (Set<?>) c) >= 0
+            : al.containsAll(c);
+    }
+
+    /**
+     * Tells whether the objects in snapshot (regarded as a set) are a
+     * superset of the given set.
+     *
+     * @return -1 if snapshot is not a superset, 0 if the two sets
+     * contain precisely the same elements, and 1 if snapshot is a
+     * proper superset of the given set
+     */
+    private static int compareSets(Object[] snapshot, Set<?> set) {
+        // Uses O(n^2) algorithm, that is only appropriate for small
+        // sets, which CopyOnWriteArraySets should be.
+        //
+        // Optimize up to O(n) if the two sets share a long common prefix,
+        // as might happen if one set was created as a copy of the other set.
+
+        final int len = snapshot.length;
+        // Mark matched elements to avoid re-checking
+        final boolean[] matched = new boolean[len];
+
+        // j is the largest int with matched[i] true for { i | 0 <= i < j }
+        int j = 0;
+        outer: for (Object x : set) {
+            for (int i = j; i < len; i++) {
+                if (!matched[i] && Objects.equals(x, snapshot[i])) {
+                    matched[i] = true;
+                    if (i == j)
+                        do { j++; } while (j < len && matched[j]);
+                    continue outer;
+                }
+            }
+            return -1;
+        }
+        return (j == len) ? 0 : 1;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present.  If the specified collection is also a
+     * set, the {@code addAll} operation effectively modifies this set so
+     * that its value is the <i>union</i> of the two sets.  The behavior of
+     * this operation is undefined if the specified collection is modified
+     * while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        return al.addAllAbsent(c) > 0;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection.  If the specified collection is also a set,
+     * this operation effectively modifies this set so that its value is the
+     * <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        return al.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.  In other words, removes from this set all of
+     * its elements that are not contained in the specified collection.  If
+     * the specified collection is also a set, this operation effectively
+     * modifies this set so that its value is the <i>intersection</i> of the
+     * two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        return al.retainAll(c);
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set
+     * in the order in which these elements were added.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the set
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this set
+     */
+    public Iterator<E> iterator() {
+        return al.iterator();
+    }
+
+    /**
+     * Compares the specified object with this set for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link Set} and the elements
+     * returned by an {@linkplain Set#iterator() iterator} over the
+     * specified set are the same as the elements returned by an
+     * iterator over this set.  More formally, the two iterators are
+     * considered to return the same elements if they return the same
+     * number of elements and for every element {@code e1} returned by
+     * the iterator over the specified set, there is an element
+     * {@code e2} returned by the iterator over this set such that
+     * {@code Objects.equals(e1, e2)}.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        return (o == this)
+            || ((o instanceof Set)
+                && compareSets(al.getArray(), (Set<?>) o) == 0);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        return al.removeIf(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        al.forEach(action);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set in the order
+     * in which these elements were added.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the set
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
+    }
+}
diff --git a/android-35/java/util/concurrent/CountDownLatch.java b/android-35/java/util/concurrent/CountDownLatch.java
new file mode 100644
index 0000000..3b41b49
--- /dev/null
+++ b/android-35/java/util/concurrent/CountDownLatch.java
@@ -0,0 +1,314 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A synchronization aid that allows one or more threads to wait until
+ * a set of operations being performed in other threads completes.
+ *
+ * <p>A {@code CountDownLatch} is initialized with a given <em>count</em>.
+ * The {@link #await await} methods block until the current count reaches
+ * zero due to invocations of the {@link #countDown} method, after which
+ * all waiting threads are released and any subsequent invocations of
+ * {@link #await await} return immediately.  This is a one-shot phenomenon
+ * -- the count cannot be reset.  If you need a version that resets the
+ * count, consider using a {@link CyclicBarrier}.
+ *
+ * <p>A {@code CountDownLatch} is a versatile synchronization tool
+ * and can be used for a number of purposes.  A
+ * {@code CountDownLatch} initialized with a count of one serves as a
+ * simple on/off latch, or gate: all threads invoking {@link #await await}
+ * wait at the gate until it is opened by a thread invoking {@link
+ * #countDown}.  A {@code CountDownLatch} initialized to <em>N</em>
+ * can be used to make one thread wait until <em>N</em> threads have
+ * completed some action, or some action has been completed N times.
+ *
+ * <p>A useful property of a {@code CountDownLatch} is that it
+ * doesn't require that threads calling {@code countDown} wait for
+ * the count to reach zero before proceeding, it simply prevents any
+ * thread from proceeding past an {@link #await await} until all
+ * threads could pass.
+ *
+ * <p><b>Sample usage:</b> Here is a pair of classes in which a group
+ * of worker threads use two countdown latches:
+ * <ul>
+ * <li>The first is a start signal that prevents any worker from proceeding
+ * until the driver is ready for them to proceed;
+ * <li>The second is a completion signal that allows the driver to wait
+ * until all workers have completed.
+ * </ul>
+ *
+ * <pre> {@code
+ * class Driver { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch startSignal = new CountDownLatch(1);
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       new Thread(new Worker(startSignal, doneSignal)).start();
+ *
+ *     doSomethingElse();            // don't let run yet
+ *     startSignal.countDown();      // let all threads proceed
+ *     doSomethingElse();
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class Worker implements Runnable {
+ *   private final CountDownLatch startSignal;
+ *   private final CountDownLatch doneSignal;
+ *   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
+ *     this.startSignal = startSignal;
+ *     this.doneSignal = doneSignal;
+ *   }
+ *   public void run() {
+ *     try {
+ *       startSignal.await();
+ *       doWork();
+ *       doneSignal.countDown();
+ *     } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</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
+ * counts down on the latch, and queue all the Runnables to an
+ * Executor.  When all sub-parts are complete, the coordinating thread
+ * will be able to pass through await. (When threads must repeatedly
+ * count down in this way, instead use a {@link CyclicBarrier}.)
+ *
+ * <pre> {@code
+ * class Driver2 { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *     Executor e = ...;
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       e.execute(new WorkerRunnable(doneSignal, i));
+ *
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class WorkerRunnable implements Runnable {
+ *   private final CountDownLatch doneSignal;
+ *   private final int i;
+ *   WorkerRunnable(CountDownLatch doneSignal, int i) {
+ *     this.doneSignal = doneSignal;
+ *     this.i = i;
+ *   }
+ *   public void run() {
+ *     doWork();
+ *     doneSignal.countDown();
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Until the count reaches
+ * zero, actions in a thread prior to calling
+ * {@code countDown()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful return from a corresponding
+ * {@code await()} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CountDownLatch {
+    /**
+     * Synchronization control For CountDownLatch.
+     * Uses AQS state to represent count.
+     */
+    private static final class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 4982264981922014374L;
+
+        Sync(int count) {
+            setState(count);
+        }
+
+        int getCount() {
+            return getState();
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return (getState() == 0) ? 1 : -1;
+        }
+
+        protected boolean tryReleaseShared(int releases) {
+            // Decrement count; signal when transition to zero
+            for (;;) {
+                int c = getState();
+                if (c == 0)
+                    return false;
+                int nextc = c - 1;
+                if (compareAndSetState(c, nextc))
+                    return nextc == 0;
+            }
+        }
+    }
+
+    private final Sync sync;
+
+    /**
+     * Constructs a {@code CountDownLatch} initialized with the given count.
+     *
+     * @param count the number of times {@link #countDown} must be invoked
+     *        before threads can pass through {@link #await}
+     * @throws IllegalArgumentException if {@code count} is negative
+     */
+    public CountDownLatch(int count) {
+        if (count < 0) throw new IllegalArgumentException("count < 0");
+        this.sync = new Sync(count);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the current count is zero then this method returns immediately.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of two things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public void await() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted},
+     * or the specified waiting time elapses.
+     *
+     * <p>If the current count is zero then this method returns immediately
+     * with the value {@code true}.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of three things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the count reaches zero then the method returns with the
+     * value {@code true}.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if the count reached zero and {@code false}
+     *         if the waiting time elapsed before the count reached zero
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public boolean await(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Decrements the count of the latch, releasing all waiting threads if
+     * the count reaches zero.
+     *
+     * <p>If the current count is greater than zero then it is decremented.
+     * If the new count is zero then all waiting threads are re-enabled for
+     * thread scheduling purposes.
+     *
+     * <p>If the current count equals zero then nothing happens.
+     */
+    public void countDown() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Returns the current count.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the current count
+     */
+    public long getCount() {
+        return sync.getCount();
+    }
+
+    /**
+     * Returns a string identifying this latch, as well as its state.
+     * The state, in brackets, includes the String {@code "Count ="}
+     * followed by the current count.
+     *
+     * @return a string identifying this latch, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Count = " + sync.getCount() + "]";
+    }
+}
diff --git a/android-35/java/util/concurrent/CountedCompleter.java b/android-35/java/util/concurrent/CountedCompleter.java
new file mode 100644
index 0000000..549e1c7
--- /dev/null
+++ b/android-35/java/util/concurrent/CountedCompleter.java
@@ -0,0 +1,791 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/**
+ * A {@link ForkJoinTask} with a completion action performed when
+ * triggered and there are no remaining pending actions.
+ * CountedCompleters are in general more robust in the
+ * presence of subtask stalls and blockage than are other forms of
+ * ForkJoinTasks, but are less intuitive to program.  Uses of
+ * CountedCompleter are similar to those of other completion based
+ * components (such as {@link java.nio.channels.CompletionHandler})
+ * except that multiple <em>pending</em> completions may be necessary
+ * to trigger the completion action {@link #onCompletion(CountedCompleter)},
+ * not just one.
+ * Unless initialized otherwise, the {@linkplain #getPendingCount pending
+ * count} starts at zero, but may be (atomically) changed using
+ * methods {@link #setPendingCount}, {@link #addToPendingCount}, and
+ * {@link #compareAndSetPendingCount}. Upon invocation of {@link
+ * #tryComplete}, if the pending action count is nonzero, it is
+ * decremented; otherwise, the completion action is performed, and if
+ * this completer itself has a completer, the process is continued
+ * with its completer.  As is the case with related synchronization
+ * components such as {@link Phaser} and {@link Semaphore}, these methods
+ * affect only internal counts; they do not establish any further
+ * internal bookkeeping. In particular, the identities of pending
+ * tasks are not maintained. As illustrated below, you can create
+ * subclasses that do record some or all pending tasks or their
+ * results when needed.  As illustrated below, utility methods
+ * supporting customization of completion traversals are also
+ * provided. However, because CountedCompleters provide only basic
+ * synchronization mechanisms, it may be useful to create further
+ * abstract subclasses that maintain linkages, fields, and additional
+ * support methods appropriate for a set of related usages.
+ *
+ * <p>A concrete CountedCompleter class must define method {@link
+ * #compute}, that should in most cases (as illustrated below), invoke
+ * {@code tryComplete()} once before returning. The class may also
+ * optionally override method {@link #onCompletion(CountedCompleter)}
+ * to perform an action upon normal completion, and method
+ * {@link #onExceptionalCompletion(Throwable, CountedCompleter)} to
+ * perform an action upon any exception.
+ *
+ * <p>CountedCompleters most often do not bear results, in which case
+ * they are normally declared as {@code CountedCompleter<Void>}, and
+ * will always return {@code null} as a result value.  In other cases,
+ * you should override method {@link #getRawResult} to provide a
+ * result from {@code join(), invoke()}, and related methods.  In
+ * general, this method should return the value of a field (or a
+ * function of one or more fields) of the CountedCompleter object that
+ * holds the result upon completion. Method {@link #setRawResult} by
+ * default plays no role in CountedCompleters.  It is possible, but
+ * rarely applicable, to override this method to maintain other
+ * objects or fields holding result data.
+ *
+ * <p>A CountedCompleter that does not itself have a completer (i.e.,
+ * one for which {@link #getCompleter} returns {@code null}) can be
+ * used as a regular ForkJoinTask with this added functionality.
+ * However, any completer that in turn has another completer serves
+ * only as an internal helper for other computations, so its own task
+ * status (as reported in methods such as {@link ForkJoinTask#isDone})
+ * is arbitrary; this status changes only upon explicit invocations of
+ * {@link #complete}, {@link ForkJoinTask#cancel},
+ * {@link ForkJoinTask#completeExceptionally(Throwable)} or upon
+ * exceptional completion of method {@code compute}. Upon any
+ * exceptional completion, the exception may be relayed to a task's
+ * completer (and its completer, and so on), if one exists and it has
+ * not otherwise already completed. Similarly, cancelling an internal
+ * CountedCompleter has only a local effect on that completer, so is
+ * not often useful.
+ *
+ * <p><b>Sample Usages.</b>
+ *
+ * <p><b>Parallel recursive decomposition.</b> CountedCompleters may
+ * be arranged in trees similar to those often used with {@link
+ * RecursiveAction}s, although the constructions involved in setting
+ * them up typically vary. Here, the completer of each task is its
+ * parent in the computation tree. Even though they entail a bit more
+ * bookkeeping, CountedCompleters may be better choices when applying
+ * a possibly time-consuming operation (that cannot be further
+ * subdivided) to each element of an array or collection; especially
+ * when the operation takes a significantly different amount of time
+ * to complete for some elements than others, either because of
+ * intrinsic variation (for example I/O) or auxiliary effects such as
+ * garbage collection.  Because CountedCompleters provide their own
+ * continuations, other tasks need not block waiting to perform them.
+ *
+ * <p>For example, here is an initial version of a utility method that
+ * uses divide-by-two recursive decomposition to divide work into
+ * single pieces (leaf tasks). Even when work is split into individual
+ * calls, tree-based techniques are usually preferable to directly
+ * forking leaf tasks, because they reduce inter-thread communication
+ * and improve load balancing. In the recursive case, the second of
+ * each pair of subtasks to finish triggers completion of their parent
+ * (because no result combination is performed, the default no-op
+ * implementation of method {@code onCompletion} is not overridden).
+ * The utility method sets up the root task and invokes it (here,
+ * implicitly using the {@link ForkJoinPool#commonPool()}).  It is
+ * straightforward and reliable (but not optimal) to always set the
+ * pending count to the number of child tasks and call {@code
+ * tryComplete()} immediately before returning.
+ *
+ * <pre> {@code
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ *   class Task extends CountedCompleter<Void> {
+ *     final int lo, hi;
+ *     Task(Task parent, int lo, int hi) {
+ *       super(parent); this.lo = lo; this.hi = hi;
+ *     }
+ *
+ *     public void compute() {
+ *       if (hi - lo >= 2) {
+ *         int mid = (lo + hi) >>> 1;
+ *         // must set pending count before fork
+ *         setPendingCount(2);
+ *         new Task(this, mid, hi).fork(); // right child
+ *         new Task(this, lo, mid).fork(); // left child
+ *       }
+ *       else if (hi > lo)
+ *         action.accept(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ *   new Task(null, 0, array.length).invoke();
+ * }}</pre>
+ *
+ * This design can be improved by noticing that in the recursive case,
+ * the task has nothing to do after forking its right task, so can
+ * directly invoke its left task before returning. (This is an analog
+ * of tail recursion removal.)  Also, when the last action in a task
+ * is to fork or invoke a subtask (a "tail call"), the call to {@code
+ * tryComplete()} can be optimized away, at the cost of making the
+ * pending count look "off by one".
+ *
+ * <pre> {@code
+ *     public void compute() {
+ *       if (hi - lo >= 2) {
+ *         int mid = (lo + hi) >>> 1;
+ *         setPendingCount(1); // looks off by one, but correct!
+ *         new Task(this, mid, hi).fork(); // right child
+ *         new Task(this, lo, mid).compute(); // direct invoke
+ *       } else {
+ *         if (hi > lo)
+ *           action.accept(array[lo]);
+ *         tryComplete();
+ *       }
+ *     }}</pre>
+ *
+ * As a further optimization, notice that the left task need not even exist.
+ * Instead of creating a new one, we can continue using the original task,
+ * and add a pending count for each fork.  Additionally, because no task
+ * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
+ * {@code tryComplete} can be replaced with {@link #propagateCompletion}.
+ *
+ * <pre> {@code
+ *     public void compute() {
+ *       int n = hi - lo;
+ *       for (; n >= 2; n /= 2) {
+ *         addToPendingCount(1);
+ *         new Task(this, lo + n/2, lo + n).fork();
+ *       }
+ *       if (n > 0)
+ *         action.accept(array[lo]);
+ *       propagateCompletion();
+ *     }}</pre>
+ *
+ * When pending counts can be precomputed, they can be established in
+ * the constructor:
+ *
+ * <pre> {@code
+ * public static <E> void forEach(E[] array, Consumer<E> action) {
+ *   class Task extends CountedCompleter<Void> {
+ *     final int lo, hi;
+ *     Task(Task parent, int lo, int hi) {
+ *       super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
+ *       this.lo = lo; this.hi = hi;
+ *     }
+ *
+ *     public void compute() {
+ *       for (int n = hi - lo; n >= 2; n /= 2)
+ *         new Task(this, lo + n/2, lo + n).fork();
+ *       action.accept(array[lo]);
+ *       propagateCompletion();
+ *     }
+ *   }
+ *   if (array.length > 0)
+ *     new Task(null, 0, array.length).invoke();
+ * }}</pre>
+ *
+ * Additional optimizations of such classes might entail specializing
+ * classes for leaf steps, subdividing by say, four, instead of two
+ * per iteration, and using an adaptive threshold instead of always
+ * subdividing down to single elements.
+ *
+ * <p><b>Searching.</b> A tree of CountedCompleters can search for a
+ * value or property in different parts of a data structure, and
+ * report a result in an {@link
+ * java.util.concurrent.atomic.AtomicReference AtomicReference} as
+ * soon as one is found. The others can poll the result to avoid
+ * unnecessary work. (You could additionally {@linkplain #cancel
+ * cancel} other tasks, but it is usually simpler and more efficient
+ * to just let them notice that the result is set and if so skip
+ * further processing.)  Illustrating again with an array using full
+ * partitioning (again, in practice, leaf tasks will almost always
+ * process more than one element):
+ *
+ * <pre> {@code
+ * class Searcher<E> extends CountedCompleter<E> {
+ *   final E[] array; final AtomicReference<E> result; final int lo, hi;
+ *   Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.result = result; this.lo = lo; this.hi = hi;
+ *   }
+ *   public E getRawResult() { return result.get(); }
+ *   public void compute() { // similar to ForEach version 3
+ *     int l = lo, h = hi;
+ *     while (result.get() == null && h >= l) {
+ *       if (h - l >= 2) {
+ *         int mid = (l + h) >>> 1;
+ *         addToPendingCount(1);
+ *         new Searcher(this, array, result, mid, h).fork();
+ *         h = mid;
+ *       }
+ *       else {
+ *         E x = array[l];
+ *         if (matches(x) && result.compareAndSet(null, x))
+ *           quietlyCompleteRoot(); // root task is now joinable
+ *         break;
+ *       }
+ *     }
+ *     tryComplete(); // normally complete whether or not found
+ *   }
+ *   boolean matches(E e) { ... } // return true if found
+ *
+ *   public static <E> E search(E[] array) {
+ *       return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * In this example, as well as others in which tasks have no other
+ * effects except to {@code compareAndSet} a common result, the
+ * trailing unconditional invocation of {@code tryComplete} could be
+ * made conditional ({@code if (result.get() == null) tryComplete();})
+ * because no further bookkeeping is required to manage completions
+ * once the root task completes.
+ *
+ * <p><b>Recording subtasks.</b> CountedCompleter tasks that combine
+ * results of multiple subtasks usually need to access these results
+ * in method {@link #onCompletion(CountedCompleter)}. As illustrated in the following
+ * class (that performs a simplified form of map-reduce where mappings
+ * and reductions are all of type {@code E}), one way to do this in
+ * divide and conquer designs is to have each subtask record its
+ * sibling, so that it can be accessed in method {@code onCompletion}.
+ * This technique applies to reductions in which the order of
+ * combining left and right results does not matter; ordered
+ * reductions require explicit left/right designations.  Variants of
+ * other streamlinings seen in the above examples may also apply.
+ *
+ * <pre> {@code
+ * class MyMapper<E> { E apply(E v) {  ...  } }
+ * class MyReducer<E> { E apply(E x, E y) {  ...  } }
+ * class MapReducer<E> extends CountedCompleter<E> {
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> sibling;
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *   }
+ *   public void compute() {
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
+ *       MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
+ *       left.sibling = right;
+ *       right.sibling = left;
+ *       setPendingCount(1); // only right is pending
+ *       right.fork();
+ *       left.compute();     // directly execute left
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *           result = mapper.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ *   public void onCompletion(CountedCompleter<?> caller) {
+ *     if (caller != this) {
+ *       MapReducer<E> child = (MapReducer<E>)caller;
+ *       MapReducer<E> sib = child.sibling;
+ *       if (sib == null || sib.result == null)
+ *         result = child.result;
+ *       else
+ *         result = reducer.apply(child.result, sib.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * Here, method {@code onCompletion} takes a form common to many
+ * completion designs that combine results. This callback-style method
+ * is triggered once per task, in either of the two different contexts
+ * in which the pending count is, or becomes, zero: (1) by a task
+ * itself, if its pending count is zero upon invocation of {@code
+ * tryComplete}, or (2) by any of its subtasks when they complete and
+ * decrement the pending count to zero. The {@code caller} argument
+ * distinguishes cases.  Most often, when the caller is {@code this},
+ * no action is necessary. Otherwise the caller argument can be used
+ * (usually via a cast) to supply a value (and/or links to other
+ * values) to be combined.  Assuming proper use of pending counts, the
+ * actions inside {@code onCompletion} occur (once) upon completion of
+ * a task and its subtasks. No additional synchronization is required
+ * within this method to ensure thread safety of accesses to fields of
+ * this task or other completed tasks.
+ *
+ * <p><b>Completion Traversals.</b> If using {@code onCompletion} to
+ * process completions is inapplicable or inconvenient, you can use
+ * methods {@link #firstComplete} and {@link #nextComplete} to create
+ * custom traversals.  For example, to define a MapReducer that only
+ * splits out right-hand tasks in the form of the third ForEach
+ * example, the completions must cooperatively reduce along
+ * unexhausted subtask links, which can be done as follows:
+ *
+ * <pre> {@code
+ * class MapReducer<E> extends CountedCompleter<E> { // version 2
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> forks, next; // record subtask forks in list
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *   public void compute() {
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       result = mapper.apply(array[l]);
+ *     // process completions by reducing along and advancing subtask links
+ *     for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ *       for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
+ *         t.result = reducer.apply(t.result, s.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length, null).invoke();
+ *   }
+ * }}</pre>
+ *
+ * <p><b>Triggers.</b> Some CountedCompleters are themselves never
+ * forked, but instead serve as bits of plumbing in other designs;
+ * including those in which the completion of one or more async tasks
+ * triggers another async task. For example:
+ *
+ * <pre> {@code
+ * class HeaderBuilder extends CountedCompleter<...> { ... }
+ * class BodyBuilder extends CountedCompleter<...> { ... }
+ * class PacketSender extends CountedCompleter<...> {
+ *   PacketSender(...) { super(null, 1); ... } // trigger on second completion
+ *   public void compute() { } // never called
+ *   public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
+ * }
+ * // sample use:
+ * PacketSender p = new PacketSender();
+ * new HeaderBuilder(p, ...).fork();
+ * new BodyBuilder(p, ...).fork();}</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
+    private static final long serialVersionUID = 5232453752276485070L;
+
+    /** This task's completer, or null if none */
+    final CountedCompleter<?> completer;
+    /** The number of pending tasks until completion */
+    volatile int pending;
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and initial pending count.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     * @param initialPendingCount the initial pending count
+     */
+    protected CountedCompleter(CountedCompleter<?> completer,
+                               int initialPendingCount) {
+        this.completer = completer;
+        this.pending = initialPendingCount;
+    }
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and an initial pending count of zero.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     */
+    protected CountedCompleter(CountedCompleter<?> completer) {
+        this.completer = completer;
+    }
+
+    /**
+     * Creates a new CountedCompleter with no completer
+     * and an initial pending count of zero.
+     */
+    protected CountedCompleter() {
+        this.completer = null;
+    }
+
+    /**
+     * The main computation performed by this task.
+     */
+    public abstract void compute();
+
+    /**
+     * Performs an action when method {@link #tryComplete} is invoked
+     * and the pending count is zero, or when the unconditional
+     * method {@link #complete} is invoked.  By default, this method
+     * does nothing. You can distinguish cases by checking the
+     * identity of the given caller argument. If not equal to {@code
+     * this}, then it is typically a subtask that may contain results
+     * (and/or links to other results) to combine.
+     *
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     */
+    public void onCompletion(CountedCompleter<?> caller) {
+    }
+
+    /**
+     * Performs an action when method {@link
+     * #completeExceptionally(Throwable)} is invoked or method {@link
+     * #compute} throws an exception, and this task has not already
+     * otherwise completed normally. On entry to this method, this task
+     * {@link ForkJoinTask#isCompletedAbnormally}.  The return value
+     * of this method controls further propagation: If {@code true}
+     * and this task has a completer that has not completed, then that
+     * completer is also completed exceptionally, with the same
+     * exception as this completer.  The default implementation of
+     * this method does nothing except return {@code true}.
+     *
+     * @param ex the exception
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     * @return {@code true} if this exception should be propagated to this
+     * task's completer, if one exists
+     */
+    public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller) {
+        return true;
+    }
+
+    /**
+     * Returns the completer established in this task's constructor,
+     * or {@code null} if none.
+     *
+     * @return the completer
+     */
+    public final CountedCompleter<?> getCompleter() {
+        return completer;
+    }
+
+    /**
+     * Returns the current pending count.
+     *
+     * @return the current pending count
+     */
+    public final int getPendingCount() {
+        return pending;
+    }
+
+    /**
+     * Sets the pending count to the given value.
+     *
+     * @param count the count
+     */
+    public final void setPendingCount(int count) {
+        pending = count;
+    }
+
+    /**
+     * Adds (atomically) the given value to the pending count.
+     *
+     * @param delta the value to add
+     */
+    public final void addToPendingCount(int delta) {
+        PENDING.getAndAdd(this, delta);
+    }
+
+    /**
+     * Sets (atomically) the pending count to the given count only if
+     * it currently holds the given expected value.
+     *
+     * @param expected the expected value
+     * @param count the new value
+     * @return {@code true} if successful
+     */
+    public final boolean compareAndSetPendingCount(int expected, int count) {
+        return PENDING.compareAndSet(this, expected, count);
+    }
+
+    // internal-only weak version
+    final boolean weakCompareAndSetPendingCount(int expected, int count) {
+        return PENDING.weakCompareAndSet(this, expected, count);
+    }
+
+    /**
+     * If the pending count is nonzero, (atomically) decrements it.
+     *
+     * @return the initial (undecremented) pending count holding on entry
+     * to this method
+     */
+    public final int decrementPendingCountUnlessZero() {
+        int c;
+        do {} while ((c = pending) != 0 &&
+                     !weakCompareAndSetPendingCount(c, c - 1));
+        return c;
+    }
+
+    /**
+     * Returns the root of the current computation; i.e., this
+     * task if it has no completer, else its completer's root.
+     *
+     * @return the root of the current computation
+     */
+    public final CountedCompleter<?> getRoot() {
+        CountedCompleter<?> a = this, p;
+        while ((p = a.completer) != null)
+            a = p;
+        return a;
+    }
+
+    /**
+     * If the pending count is nonzero, decrements the count;
+     * otherwise invokes {@link #onCompletion(CountedCompleter)}
+     * and then similarly tries to complete this task's completer,
+     * if one exists, else marks this task as complete.
+     */
+    public final void tryComplete() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                a.onCompletion(s);
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (a.weakCompareAndSetPendingCount(c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Equivalent to {@link #tryComplete} but does not invoke {@link
+     * #onCompletion(CountedCompleter)} along the completion path:
+     * If the pending count is nonzero, decrements the count;
+     * otherwise, similarly tries to complete this task's completer, if
+     * one exists, else marks this task as complete. This method may be
+     * useful in cases where {@code onCompletion} should not, or need
+     * not, be invoked for each completer in a computation.
+     */
+    public final void propagateCompletion() {
+        CountedCompleter<?> a = this, s;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (a.weakCompareAndSetPendingCount(c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Regardless of pending count, invokes
+     * {@link #onCompletion(CountedCompleter)}, marks this task as
+     * complete and further triggers {@link #tryComplete} on this
+     * task's completer, if one exists.  The given rawResult is
+     * used as an argument to {@link #setRawResult} before invoking
+     * {@link #onCompletion(CountedCompleter)} or marking this task
+     * as complete; its value is meaningful only for classes
+     * overriding {@code setRawResult}.  This method does not modify
+     * the pending count.
+     *
+     * <p>This method may be useful when forcing completion as soon as
+     * any one (versus all) of several subtask results are obtained.
+     * However, in the common (and recommended) case in which {@code
+     * setRawResult} is not overridden, this effect can be obtained
+     * more simply using {@link #quietlyCompleteRoot()}.
+     *
+     * @param rawResult the raw result
+     */
+    public void complete(T rawResult) {
+        CountedCompleter<?> p;
+        setRawResult(rawResult);
+        onCompletion(this);
+        quietlyComplete();
+        if ((p = completer) != null)
+            p.tryComplete();
+    }
+
+    /**
+     * If this task's pending count is zero, returns this task;
+     * otherwise decrements its pending count and returns {@code null}.
+     * This method is designed to be used with {@link #nextComplete} in
+     * completion traversal loops.
+     *
+     * @return this task, if pending count was zero, else {@code null}
+     */
+    public final CountedCompleter<?> firstComplete() {
+        for (int c;;) {
+            if ((c = pending) == 0)
+                return this;
+            else if (weakCompareAndSetPendingCount(c, c - 1))
+                return null;
+        }
+    }
+
+    /**
+     * If this task does not have a completer, invokes {@link
+     * ForkJoinTask#quietlyComplete} and returns {@code null}.  Or, if
+     * the completer's pending count is non-zero, decrements that
+     * pending count and returns {@code null}.  Otherwise, returns the
+     * completer.  This method can be used as part of a completion
+     * traversal loop for homogeneous task hierarchies:
+     *
+     * <pre> {@code
+     * for (CountedCompleter<?> c = firstComplete();
+     *      c != null;
+     *      c = c.nextComplete()) {
+     *   // ... process c ...
+     * }}</pre>
+     *
+     * @return the completer, or {@code null} if none
+     */
+    public final CountedCompleter<?> nextComplete() {
+        CountedCompleter<?> p;
+        if ((p = completer) != null)
+            return p.firstComplete();
+        else {
+            quietlyComplete();
+            return null;
+        }
+    }
+
+    /**
+     * Equivalent to {@code getRoot().quietlyComplete()}.
+     */
+    public final void quietlyCompleteRoot() {
+        for (CountedCompleter<?> a = this, p;;) {
+            if ((p = a.completer) == null) {
+                a.quietlyComplete();
+                return;
+            }
+            a = p;
+        }
+    }
+
+    /**
+     * If this task has not completed, attempts to process at most the
+     * given number of other unprocessed tasks for which this task is
+     * on the completion path, if any are known to exist.
+     *
+     * @param maxTasks the maximum number of tasks to process.  If
+     *                 less than or equal to zero, then no tasks are
+     *                 processed.
+     */
+    public final void helpComplete(int maxTasks) {
+        ForkJoinPool.WorkQueue q; Thread t; boolean owned;
+        if (owned = (t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonQueue();
+        if (q != null && maxTasks > 0)
+            q.helpComplete(this, owned, maxTasks);
+    }
+
+    // ForkJoinTask overrides
+
+    /**
+     * Supports ForkJoinTask exception propagation.
+     */
+    @Override
+    final int trySetException(Throwable ex) {
+        CountedCompleter<?> a = this, p = a;
+        do {} while (isExceptionalStatus(a.trySetThrown(ex)) &&
+                     a.onExceptionalCompletion(ex, p) &&
+                     (a = (p = a).completer) != null && a.status >= 0);
+        return status;
+    }
+
+    /**
+     * Implements execution conventions for CountedCompleters.
+     */
+    @Override
+    protected final boolean exec() {
+        compute();
+        return false;
+    }
+
+    /**
+     * Returns the result of the computation.  By default,
+     * returns {@code null}, which is appropriate for {@code Void}
+     * actions, but in other cases should be overridden, almost
+     * always to return a field or function of a field that
+     * holds the result upon completion.
+     *
+     * @return the result of the computation
+     */
+    @Override
+    public T getRawResult() { return null; }
+
+    /**
+     * A method that result-bearing CountedCompleters may optionally
+     * use to help maintain result data.  By default, does nothing.
+     * Overrides are not recommended. However, if this method is
+     * overridden to update existing objects or fields, then it must
+     * in general be defined to be thread-safe.
+     */
+    @Override
+    protected void setRawResult(T t) { }
+
+    // VarHandle mechanics
+    private static final VarHandle PENDING;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
+
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/CyclicBarrier.java b/android-35/java/util/concurrent/CyclicBarrier.java
new file mode 100644
index 0000000..87e498d
--- /dev/null
+++ b/android-35/java/util/concurrent/CyclicBarrier.java
@@ -0,0 +1,493 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A synchronization aid that allows a set of threads to all wait for
+ * each other to reach a common barrier point.  CyclicBarriers are
+ * useful in programs involving a fixed sized party of threads that
+ * must occasionally wait for each other. The barrier is called
+ * <em>cyclic</em> because it can be re-used after the waiting threads
+ * are released.
+ *
+ * <p>A {@code CyclicBarrier} supports an optional {@link Runnable} command
+ * that is run once per barrier point, after the last thread in the party
+ * arrives, but before any threads are released.
+ * This <em>barrier action</em> is useful
+ * for updating shared-state before any of the parties continue.
+ *
+ * <p><b>Sample usage:</b> Here is an example of using a barrier in a
+ * parallel decomposition design:
+ *
+ * <pre> {@code
+ * class Solver {
+ *   final int N;
+ *   final float[][] data;
+ *   final CyclicBarrier barrier;
+ *
+ *   class Worker implements Runnable {
+ *     int myRow;
+ *     Worker(int row) { myRow = row; }
+ *     public void run() {
+ *       while (!done()) {
+ *         processRow(myRow);
+ *
+ *         try {
+ *           barrier.await();
+ *         } catch (InterruptedException ex) {
+ *           return;
+ *         } catch (BrokenBarrierException ex) {
+ *           return;
+ *         }
+ *       }
+ *     }
+ *   }
+ *
+ *   public Solver(float[][] matrix) {
+ *     data = matrix;
+ *     N = matrix.length;
+ *     Runnable barrierAction = () -> mergeRows(...);
+ *     barrier = new CyclicBarrier(N, barrierAction);
+ *
+ *     List<Thread> threads = new ArrayList<>(N);
+ *     for (int i = 0; i < N; i++) {
+ *       Thread thread = new Thread(new Worker(i));
+ *       threads.add(thread);
+ *       thread.start();
+ *     }
+ *
+ *     // wait until done
+ *     for (Thread thread : threads)
+ *       try {
+ *         thread.join();
+ *       } catch (InterruptedException ex) { }
+ *   }
+ * }}</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 rows.
+ * If the merger determines that a solution has been found then {@code done()}
+ * will return {@code true} and each worker will terminate.
+ *
+ * <p>If the barrier action does not rely on the parties being suspended when
+ * it is executed, then any of the threads in the party could execute that
+ * action when it is released. To facilitate this, each invocation of
+ * {@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> {@code
+ * if (barrier.await() == 0) {
+ *   // log the completion of this iteration
+ * }}</pre>
+ *
+ * <p>The {@code CyclicBarrier} uses an all-or-none breakage model
+ * for failed synchronization attempts: If a thread leaves a barrier
+ * point prematurely because of interruption, failure, or timeout, all
+ * other threads waiting at that barrier point will also leave
+ * abnormally via {@link BrokenBarrierException} (or
+ * {@link InterruptedException} if they too were interrupted at about
+ * the same time).
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * {@code await()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions that are part of the barrier action, which in turn
+ * <i>happen-before</i> actions following a successful return from the
+ * corresponding {@code await()} in other threads.
+ *
+ * @see CountDownLatch
+ * @see Phaser
+ *
+ * @author Doug Lea
+ * @since 1.5
+ */
+public class CyclicBarrier {
+    /**
+     * Each use of the barrier is represented as a generation instance.
+     * The generation changes whenever the barrier is tripped, or
+     * is reset. There can be many generations associated with threads
+     * using the barrier - due to the non-deterministic way the lock
+     * may be allocated to waiting threads - but only one of these
+     * can be active at a time (the one to which {@code count} applies)
+     * and all the rest are either broken or tripped.
+     * There need not be an active generation if there has been a break
+     * but no subsequent reset.
+     */
+    private static class Generation {
+        Generation() {}                 // prevent access constructor creation
+        boolean broken;                 // initially false
+    }
+
+    /** The lock for guarding barrier entry */
+    private final ReentrantLock lock = new ReentrantLock();
+    /** Condition to wait on until tripped */
+    private final Condition trip = lock.newCondition();
+    /** The number of parties */
+    private final int parties;
+    /** The command to run when tripped */
+    private final Runnable barrierCommand;
+    /** The current generation */
+    private Generation generation = new Generation();
+
+    /**
+     * Number of parties still waiting. Counts down from parties to 0
+     * on each generation.  It is reset to parties on each new
+     * generation or when broken.
+     */
+    private int count;
+
+    /**
+     * Updates state on barrier trip and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void nextGeneration() {
+        // signal completion of last generation
+        trip.signalAll();
+        // set up next generation
+        count = parties;
+        generation = new Generation();
+    }
+
+    /**
+     * Sets current barrier generation as broken and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void breakBarrier() {
+        generation.broken = true;
+        count = parties;
+        trip.signalAll();
+    }
+
+    /**
+     * Main barrier code, covering the various policies.
+     */
+    private int dowait(boolean timed, long nanos)
+        throws InterruptedException, BrokenBarrierException,
+               TimeoutException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Generation g = generation;
+
+            if (g.broken)
+                throw new BrokenBarrierException();
+
+            if (Thread.interrupted()) {
+                breakBarrier();
+                throw new InterruptedException();
+            }
+
+            int index = --count;
+            if (index == 0) {  // tripped
+                Runnable command = barrierCommand;
+                if (command != null) {
+                    try {
+                        command.run();
+                    } catch (Throwable ex) {
+                        breakBarrier();
+                        throw ex;
+                    }
+                }
+                nextGeneration();
+                return 0;
+            }
+
+            // loop until tripped, broken, interrupted, or timed out
+            for (;;) {
+                try {
+                    if (!timed)
+                        trip.await();
+                    else if (nanos > 0L)
+                        nanos = trip.awaitNanos(nanos);
+                } catch (InterruptedException ie) {
+                    if (g == generation && ! g.broken) {
+                        breakBarrier();
+                        throw ie;
+                    } else {
+                        // We're about to finish waiting even if we had not
+                        // been interrupted, so this interrupt is deemed to
+                        // "belong" to subsequent execution.
+                        Thread.currentThread().interrupt();
+                    }
+                }
+
+                if (g.broken)
+                    throw new BrokenBarrierException();
+
+                if (g != generation)
+                    return index;
+
+                if (timed && nanos <= 0L) {
+                    breakBarrier();
+                    throw new TimeoutException();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and which
+     * will execute the given barrier action when the barrier is tripped,
+     * performed by the last thread entering the barrier.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @param barrierAction the command to execute when the barrier is
+     *        tripped, or {@code null} if there is no action
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties, Runnable barrierAction) {
+        if (parties <= 0) throw new IllegalArgumentException();
+        this.parties = parties;
+        this.count = parties;
+        this.barrierCommand = barrierAction;
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and
+     * does not perform a predefined action when the barrier is tripped.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties) {
+        this(parties, null);
+    }
+
+    /**
+     * Returns the number of parties required to trip this barrier.
+     *
+     * @return the number of parties required to trip this barrier
+     */
+    public int getParties() {
+        return parties;
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting,
+     * then all other waiting threads will throw
+     * {@link BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was
+     *         broken when {@code await} was called, or the barrier
+     *         action (if present) failed due to an exception
+     */
+    public int await() throws InterruptedException, BrokenBarrierException {
+        try {
+            return dowait(false, 0L);
+        } catch (TimeoutException toe) {
+            throw new Error(toe); // cannot happen
+        }
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier, or the specified waiting time elapses.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>The specified timeout elapses; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link TimeoutException}
+     * is thrown. If the time is less than or equal to zero, the
+     * method will not wait at all.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while
+     * waiting, then all other waiting threads will throw {@link
+     * BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @param timeout the time to wait for the barrier
+     * @param unit the time unit of the timeout parameter
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws TimeoutException if the specified timeout elapses.
+     *         In this case the barrier will be broken.
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was broken
+     *         when {@code await} was called, or the barrier action (if
+     *         present) failed due to an exception
+     */
+    public int await(long timeout, TimeUnit unit)
+        throws InterruptedException,
+               BrokenBarrierException,
+               TimeoutException {
+        return dowait(true, unit.toNanos(timeout));
+    }
+
+    /**
+     * Queries if this barrier is in a broken state.
+     *
+     * @return {@code true} if one or more parties broke out of this
+     *         barrier due to interruption or timeout since
+     *         construction or the last reset, or a barrier action
+     *         failed due to an exception; {@code false} otherwise.
+     */
+    public boolean isBroken() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return generation.broken;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Resets the barrier to its initial state.  If any parties are
+     * currently waiting at the barrier, they will return with a
+     * {@link BrokenBarrierException}. Note that resets <em>after</em>
+     * a breakage has occurred for other reasons can be complicated to
+     * carry out; threads need to re-synchronize in some other way,
+     * and choose one to perform the reset.  It may be preferable to
+     * instead create a new barrier for subsequent use.
+     */
+    public void reset() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            breakBarrier();   // break the current generation
+            nextGeneration(); // start a new generation
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the number of parties currently waiting at the barrier.
+     * This method is primarily useful for debugging and assertions.
+     *
+     * @return the number of parties currently blocked in {@link #await}
+     */
+    public int getNumberWaiting() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return parties - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/DelayQueue.java b/android-35/java/util/concurrent/DelayQueue.java
new file mode 100644
index 0000000..bf0858d
--- /dev/null
+++ b/android-35/java/util/concurrent/DelayQueue.java
@@ -0,0 +1,537 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} of
+ * {@code Delayed} elements, in which an element can only be taken
+ * when its delay has expired.  The <em>head</em> of the queue is that
+ * {@code Delayed} element whose delay expired furthest in the
+ * past.  If no delay has expired there is no head and {@code poll}
+ * will return {@code null}. Expiration occurs when an element's
+ * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less
+ * than or equal to zero.  Even though unexpired elements cannot be
+ * removed using {@code take} or {@code poll}, they are otherwise
+ * treated as normal elements. For example, the {@code size} method
+ * returns the count of both expired and unexpired elements.
+ * This queue does not permit null elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link 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.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
+    implements BlockingQueue<E> {
+
+    private final transient ReentrantLock lock = new ReentrantLock();
+    private final PriorityQueue<E> q = new PriorityQueue<E>();
+
+    /**
+     * Thread designated to wait for the element at the head of
+     * the queue.  This variant of the Leader-Follower pattern
+     * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+     * minimize unnecessary timed waiting.  When a thread becomes
+     * the leader, it waits only for the next delay to elapse, but
+     * other threads await indefinitely.  The leader thread must
+     * signal some other thread before returning from take() or
+     * poll(...), unless some other thread becomes leader in the
+     * interim.  Whenever the head of the queue is replaced with
+     * an element with an earlier expiration time, the leader
+     * field is invalidated by being reset to null, and some
+     * waiting thread, but not necessarily the current leader, is
+     * signalled.  So waiting threads must be prepared to acquire
+     * and lose leadership while waiting.
+     */
+    private Thread leader;
+
+    /**
+     * Condition signalled when a newer element becomes available
+     * at the head of the queue or a new thread may need to
+     * become leader.
+     */
+    private final Condition available = lock.newCondition();
+
+    /**
+     * Creates a new {@code DelayQueue} that is initially empty.
+     */
+    public DelayQueue() {}
+
+    /**
+     * Creates a {@code DelayQueue} initially containing the elements of the
+     * given collection of {@link Delayed} instances.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public DelayQueue(Collection<? extends E> c) {
+        this.addAll(c);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.offer(e);
+            if (q.peek() == e) {
+                leader = null;
+                available.signal();
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) {
+        offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @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}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e);
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, or returns {@code null}
+     * if this queue has no elements with an expired delay.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue has no elements with an expired delay
+     */
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E first = q.peek();
+            return (first == null || first.getDelay(NANOSECONDS) > 0)
+                ? null
+                : q.poll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null)
+                    available.await();
+                else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    first = null; // don't retain ref while waiting
+                    if (leader != null)
+                        available.await();
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            available.awaitNanos(delay);
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue,
+     * or the specified wait time expires.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element with
+     *         an expired delay becomes available
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null) {
+                    if (nanos <= 0L)
+                        return null;
+                    else
+                        nanos = available.awaitNanos(nanos);
+                } else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    if (nanos <= 0L)
+                        return null;
+                    first = null; // don't retain ref while waiting
+                    if (nanos < delay || leader != null)
+                        nanos = available.awaitNanos(nanos);
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            long timeLeft = available.awaitNanos(delay);
+                            nanos -= delay - timeLeft;
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue, or
+     * returns {@code null} if this queue is empty.  Unlike
+     * {@code poll}, if no expired elements are available in the queue,
+     * this method returns the element that will expire next,
+     * if one exists.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue is empty
+     */
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.peek();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.size();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E first;
+                 n < maxElements
+                     && (first = q.peek()) != null
+                     && first.getDelay(NANOSECONDS) <= 0;) {
+                c.add(first);   // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this delay queue.
+     * The queue will be empty after this call returns.
+     * Elements with an unexpired delay are not waited for; they are
+     * simply discarded from the queue.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.clear();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code DelayQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE}
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>The following code can be used to dump a delay queue into a newly
+     * allocated array of {@code Delayed}:
+     *
+     * <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray(a);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Removes a single instance of the specified element from this
+     * queue, if it is present, whether or not it has expired.
+     */
+    public boolean remove(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.remove(o);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    private class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet;          // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            lastRet = -1;
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            return (E)array[lastRet = cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEQ(array[lastRet]);
+            lastRet = -1;
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/Delayed.java b/android-35/java/util/concurrent/Delayed.java
new file mode 100644
index 0000000..5da1ec8
--- /dev/null
+++ b/android-35/java/util/concurrent/Delayed.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A mix-in style interface for marking objects that should be
+ * acted upon after a given delay.
+ *
+ * <p>An implementation of this interface must define a
+ * {@code compareTo} method that provides an ordering consistent with
+ * its {@code getDelay} method.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Delayed extends Comparable<Delayed> {
+
+    /**
+     * Returns the remaining delay associated with this object, in the
+     * given time unit.
+     *
+     * @param unit the time unit
+     * @return the remaining delay; zero or negative values indicate
+     * that the delay has already elapsed
+     */
+    long getDelay(TimeUnit unit);
+}
diff --git a/android-35/java/util/concurrent/Exchanger.java b/android-35/java/util/concurrent/Exchanger.java
new file mode 100644
index 0000000..ce01944
--- /dev/null
+++ b/android-35/java/util/concurrent/Exchanger.java
@@ -0,0 +1,649 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, 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/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A synchronization point at which threads can pair and swap elements
+ * within pairs.  Each thread presents some object on entry to the
+ * {@link #exchange exchange} method, matches with a partner thread,
+ * and receives its partner's object on return.  An Exchanger may be
+ * viewed as a bidirectional form of a {@link SynchronousQueue}.
+ * Exchangers may be useful in applications such as genetic algorithms
+ * and pipeline designs.
+ *
+ * <p><b>Sample Usage:</b>
+ * Here are the highlights of a class that uses an {@code Exchanger}
+ * 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
+ * class FillAndEmpty {
+ *   Exchanger<DataBuffer> exchanger = new Exchanger<>();
+ *   DataBuffer initialEmptyBuffer = ...; // a made-up type
+ *   DataBuffer initialFullBuffer = ...;
+ *
+ *   class FillingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialEmptyBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           addToBuffer(currentBuffer);
+ *           if (currentBuffer.isFull())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ...}
+ *     }
+ *   }
+ *
+ *   class EmptyingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialFullBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           takeFromBuffer(currentBuffer);
+ *           if (currentBuffer.isEmpty())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ...}
+ *     }
+ *   }
+ *
+ *   void start() {
+ *     new Thread(new FillingLoop()).start();
+ *     new Thread(new EmptyingLoop()).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: For each pair of threads that
+ * successfully exchange objects via an {@code Exchanger}, actions
+ * prior to the {@code exchange()} in each thread
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those subsequent to a return from the corresponding {@code exchange()}
+ * in the other thread.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <V> The type of objects that may be exchanged
+ */
+public class Exchanger<V> {
+
+    /*
+     * Overview: The core algorithm is, for an exchange "slot",
+     * and a participant (caller) with an item:
+     *
+     * for (;;) {
+     *   if (slot is empty) {                       // offer
+     *     place item in a Node;
+     *     if (can CAS slot from empty to node) {
+     *       wait for release;
+     *       return matching item in node;
+     *     }
+     *   }
+     *   else if (can CAS slot from node to empty) { // release
+     *     get the item in node;
+     *     set matching item in node;
+     *     release waiting thread;
+     *   }
+     *   // else retry on CAS failure
+     * }
+     *
+     * This is among the simplest forms of a "dual data structure" --
+     * see Scott and Scherer's DISC 04 paper and
+     * http://www.cs.rochester.edu/research/synchronization/pseudocode/duals.html
+     *
+     * This works great in principle. But in practice, like many
+     * algorithms centered on atomic updates to a single location, it
+     * scales horribly when there are more than a few participants
+     * using the same Exchanger. So the implementation instead uses a
+     * form of elimination arena, that spreads out this contention by
+     * arranging that some threads typically use different slots,
+     * while still ensuring that eventually, any two parties will be
+     * able to exchange items. That is, we cannot completely partition
+     * across threads, but instead give threads arena indices that
+     * will on average grow under contention and shrink under lack of
+     * contention. We approach this by defining the Nodes that we need
+     * anyway as ThreadLocals, and include in them per-thread index
+     * and related bookkeeping state. (We can safely reuse per-thread
+     * nodes rather than creating them fresh each time because slots
+     * alternate between pointing to a node vs null, so cannot
+     * encounter ABA problems. However, we do need some care in
+     * resetting them between uses.)
+     *
+     * Implementing an effective arena requires allocating a bunch of
+     * space, so we only do so upon detecting contention (except on
+     * uniprocessors, where they wouldn't help, so aren't used).
+     * Otherwise, exchanges use the single-slot slotExchange method.
+     * On contention, not only must the slots be in different
+     * locations, but the locations must not encounter memory
+     * contention due to being on the same cache line (or more
+     * generally, the same coherence unit).  Because, as of this
+     * writing, there is no way to determine cacheline size, we define
+     * a value that is enough for common platforms.  Additionally,
+     * extra care elsewhere is taken to avoid other false/unintended
+     * sharing and to enhance locality, including adding padding (via
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field.
+     *
+     * The arena starts out with only one used slot. We expand the
+     * effective arena size by tracking collisions; i.e., failed CASes
+     * while trying to exchange. By nature of the above algorithm, the
+     * only kinds of collision that reliably indicate contention are
+     * when two attempted releases collide -- one of two attempted
+     * offers can legitimately fail to CAS without indicating
+     * contention by more than one other thread. (Note: it is possible
+     * but not worthwhile to more precisely detect contention by
+     * reading slot values after CAS failures.)  When a thread has
+     * collided at each slot within the current arena bound, it tries
+     * to expand the arena size by one. We track collisions within
+     * bounds by using a version (sequence) number on the "bound"
+     * field, and conservatively reset collision counts when a
+     * participant notices that bound has been updated (in either
+     * direction).
+     *
+     * The effective arena size is reduced (when there is more than
+     * one slot) by giving up on waiting after a while and trying to
+     * decrement the arena size on expiration. The value of "a while"
+     * is an empirical matter.  We implement by piggybacking on the
+     * use of spin->yield->block that is essential for reasonable
+     * waiting performance anyway -- in a busy exchanger, offers are
+     * usually almost immediately released, in which case context
+     * switching on multiprocessors is extremely slow/wasteful.  Arena
+     * waits just omit the blocking part, and instead cancel. The spin
+     * count is empirically chosen to be a value that avoids blocking
+     * 99% of the time under maximum sustained exchange rates on a
+     * range of test machines. Spins and yields entail some limited
+     * randomness (using a cheap xorshift) to avoid regular patterns
+     * that can induce unproductive grow/shrink cycles. (Using a
+     * pseudorandom also helps regularize spin cycle duration by
+     * making branches unpredictable.)  Also, during an offer, a
+     * waiter can "know" that it will be released when its slot has
+     * changed, but cannot yet proceed until match is set.  In the
+     * mean time it cannot cancel the offer, so instead spins/yields.
+     * Note: It is possible to avoid this secondary check by changing
+     * the linearization point to be a CAS of the match field (as done
+     * in one case in the Scott & Scherer DISC paper), which also
+     * increases asynchrony a bit, at the expense of poorer collision
+     * detection and inability to always reuse per-thread nodes. So
+     * the current scheme is typically a better tradeoff.
+     *
+     * On collisions, indices traverse the arena cyclically in reverse
+     * order, restarting at the maximum index (which will tend to be
+     * sparsest) when bounds change. (On expirations, indices instead
+     * are halved until reaching 0.) It is possible (and has been
+     * tried) to use randomized, prime-value-stepped, or double-hash
+     * style traversal instead of simple cyclic traversal to reduce
+     * bunching.  But empirically, whatever benefits these may have
+     * don't overcome their added overhead: We are managing operations
+     * that occur very quickly unless there is sustained contention,
+     * so simpler/faster control policies work better than more
+     * accurate but slower ones.
+     *
+     * Because we use expiration for arena size control, we cannot
+     * throw TimeoutExceptions in the timed version of the public
+     * exchange method until the arena size has shrunken to zero (or
+     * the arena isn't enabled). This may delay response to timeout
+     * but is still within spec.
+     *
+     * Essentially all of the implementation is in methods
+     * slotExchange and arenaExchange. These have similar overall
+     * structure, but differ in too many details to combine. The
+     * slotExchange method uses the single Exchanger field "slot"
+     * rather than arena array elements. However, it still needs
+     * minimal collision detection to trigger arena construction.
+     * (The messiest part is making sure interrupt status and
+     * InterruptedExceptions come out right during transitions when
+     * both methods may be called. This is done by using null return
+     * as a sentinel to recheck interrupt status.)
+     *
+     * As is too common in this sort of code, methods are monolithic
+     * because most of the logic relies on reads of fields that are
+     * maintained as local variables so can't be nicely factored --
+     * mainly, here, bulky spin->yield->block/cancel code.  Note that
+     * field Node.item is not declared as volatile even though it is
+     * read by releasing threads, because they only do so after CAS
+     * operations that must precede access, and all uses by the owning
+     * thread are otherwise acceptably ordered by other operations.
+     * (Because the actual points of atomicity are slot CASes, it
+     * would also be legal for the write to Node.match in a release to
+     * be weaker than a full volatile write. However, this is not done
+     * because it could allow further postponement of the write,
+     * delaying progress.)
+     */
+
+    /**
+     * The index distance (as a shift value) between any two used slots
+     * in the arena, spacing them out to avoid false sharing.
+     */
+    private static final int ASHIFT = 5;
+
+    /**
+     * The maximum supported arena index. The maximum allocatable
+     * arena size is MMASK + 1. Must be a power of two minus one, less
+     * than (1<<(31-ASHIFT)). The cap of 255 (0xff) more than suffices
+     * for the expected scaling limits of the main algorithms.
+     */
+    private static final int MMASK = 0xff;
+
+    /**
+     * Unit for sequence/version bits of bound field. Each successful
+     * change to the bound also adds SEQ.
+     */
+    private static final int SEQ = MMASK + 1;
+
+    /** The number of CPUs, for sizing and spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The maximum slot index of the arena: The number of slots that
+     * can in principle hold all threads without contention, or at
+     * most the maximum indexable value.
+     */
+    static final int FULL = (NCPU >= (MMASK << 1)) ? MMASK : NCPU >>> 1;
+
+    /**
+     * The bound for spins while waiting for a match. The actual
+     * number of iterations will on average be about twice this value
+     * due to randomization. Note: Spinning is disabled when NCPU==1.
+     */
+    private static final int SPINS = 1 << 10;
+
+    /**
+     * Value representing null arguments/returns from public
+     * methods. Needed because the API originally didn't disallow null
+     * arguments, which it should have.
+     */
+    private static final Object NULL_ITEM = new Object();
+
+    /**
+     * Sentinel value returned by internal exchange methods upon
+     * timeout, to avoid need for separate timed versions of these
+     * methods.
+     */
+    private static final Object TIMED_OUT = new Object();
+
+    /**
+     * Nodes hold partially exchanged data, plus other per-thread
+     * bookkeeping. Padded via @Contended to reduce memory contention.
+     */
+    @jdk.internal.vm.annotation.Contended
+    static final class Node {
+        int index;              // Arena index
+        int bound;              // Last recorded value of Exchanger.bound
+        int collides;           // Number of CAS failures at current bound
+        int hash;               // Pseudo-random for spins
+        Object item;            // This thread's current item
+        volatile Object match;  // Item provided by releasing thread
+        volatile Thread parked; // Set to this thread when parked, else null
+    }
+
+    /** The corresponding thread local class */
+    static final class Participant extends ThreadLocal<Node> {
+        public Node initialValue() { return new Node(); }
+    }
+
+    /**
+     * Per-thread state.
+     */
+    private final Participant participant;
+
+    /**
+     * Elimination array; null until enabled (within slotExchange).
+     * Element accesses use emulation of volatile gets and CAS.
+     */
+    private volatile Node[] arena;
+
+    /**
+     * Slot used until contention detected.
+     */
+    private volatile Node slot;
+
+    /**
+     * The index of the largest valid arena position, OR'ed with SEQ
+     * number in high bits, incremented on each update.  The initial
+     * update from 0 to SEQ is used to ensure that the arena array is
+     * constructed only once.
+     */
+    private volatile int bound;
+
+    /**
+     * Exchange function when arenas enabled. See above for explanation.
+     *
+     * @param item the (non-null) item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if interrupted; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object arenaExchange(Object item, boolean timed, long ns) {
+        Node[] a = arena;
+        int alen = a.length;
+        Node p = participant.get();
+        for (int i = p.index;;) {                      // access slot at i
+            int b, m, c;
+            int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
+            if (j < 0 || j >= alen)
+                j = alen - 1;
+            Node q = (Node)AA.getAcquire(a, j);
+            if (q != null && AA.compareAndSet(a, j, q, null)) {
+                Object v = q.item;                     // release
+                q.match = item;
+                Thread w = q.parked;
+                if (w != null)
+                    LockSupport.unpark(w);
+                return v;
+            }
+            else if (i <= (m = (b = bound) & MMASK) && q == null) {
+                p.item = item;                         // offer
+                if (AA.compareAndSet(a, j, null, p)) {
+                    long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
+                    Thread t = Thread.currentThread(); // wait
+                    for (int h = p.hash, spins = SPINS;;) {
+                        Object v = p.match;
+                        if (v != null) {
+                            MATCH.setRelease(p, null);
+                            p.item = null;             // clear for next use
+                            p.hash = h;
+                            return v;
+                        }
+                        else if (spins > 0) {
+                            h ^= h << 1; h ^= h >>> 3; h ^= h << 10; // xorshift
+                            if (h == 0)                // initialize hash
+                                h = SPINS | (int)t.getId();
+                            else if (h < 0 &&          // approx 50% true
+                                     (--spins & ((SPINS >>> 1) - 1)) == 0)
+                                Thread.yield();        // two yields per wait
+                        }
+                        else if (AA.getAcquire(a, j) != p)
+                            spins = SPINS;       // releaser hasn't set match yet
+                        else if (!t.isInterrupted() && m == 0 &&
+                                 (!timed ||
+                                  (ns = end - System.nanoTime()) > 0L)) {
+                            p.parked = t;              // minimize window
+                            if (AA.getAcquire(a, j) == p) {
+                                if (ns == 0L)
+                                    LockSupport.park(this);
+                                else
+                                    LockSupport.parkNanos(this, ns);
+                            }
+                            p.parked = null;
+                        }
+                        else if (AA.getAcquire(a, j) == p &&
+                                 AA.compareAndSet(a, j, p, null)) {
+                            if (m != 0)                // try to shrink
+                                BOUND.compareAndSet(this, b, b + SEQ - 1);
+                            p.item = null;
+                            p.hash = h;
+                            i = p.index >>>= 1;        // descend
+                            if (Thread.interrupted())
+                                return null;
+                            if (timed && m == 0 && ns <= 0L)
+                                return TIMED_OUT;
+                            break;                     // expired; restart
+                        }
+                    }
+                }
+                else
+                    p.item = null;                     // clear offer
+            }
+            else {
+                if (p.bound != b) {                    // stale; reset
+                    p.bound = b;
+                    p.collides = 0;
+                    i = (i != m || m == 0) ? m : m - 1;
+                }
+                else if ((c = p.collides) < m || m == FULL ||
+                         !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
+                    p.collides = c + 1;
+                    i = (i == 0) ? m : i - 1;          // cyclically traverse
+                }
+                else
+                    i = m + 1;                         // grow
+                p.index = i;
+            }
+        }
+    }
+
+    /**
+     * Exchange function used until arenas enabled. See above for explanation.
+     *
+     * @param item the item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if either the arena
+     * was enabled or the thread was interrupted before completion; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object slotExchange(Object item, boolean timed, long ns) {
+        Node p = participant.get();
+        Thread t = Thread.currentThread();
+        if (t.isInterrupted()) // preserve interrupt status so caller can recheck
+            return null;
+
+        for (Node q;;) {
+            if ((q = slot) != null) {
+                if (SLOT.compareAndSet(this, q, null)) {
+                    Object v = q.item;
+                    q.match = item;
+                    Thread w = q.parked;
+                    if (w != null)
+                        LockSupport.unpark(w);
+                    return v;
+                }
+                // create arena on contention, but continue until slot null
+                if (NCPU > 1 && bound == 0 &&
+                    BOUND.compareAndSet(this, 0, SEQ))
+                    arena = new Node[(FULL + 2) << ASHIFT];
+            }
+            else if (arena != null)
+                return null; // caller must reroute to arenaExchange
+            else {
+                p.item = item;
+                if (SLOT.compareAndSet(this, null, p))
+                    break;
+                p.item = null;
+            }
+        }
+
+        // await release
+        int h = p.hash;
+        long end = timed ? System.nanoTime() + ns : 0L;
+        int spins = (NCPU > 1) ? SPINS : 1;
+        Object v;
+        while ((v = p.match) == null) {
+            if (spins > 0) {
+                h ^= h << 1; h ^= h >>> 3; h ^= h << 10;
+                if (h == 0)
+                    h = SPINS | (int)t.getId();
+                else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
+                    Thread.yield();
+            }
+            else if (slot != p)
+                spins = SPINS;
+            else if (!t.isInterrupted() && arena == null &&
+                     (!timed || (ns = end - System.nanoTime()) > 0L)) {
+                p.parked = t;
+                if (slot == p) {
+                    if (ns == 0L)
+                        LockSupport.park(this);
+                    else
+                        LockSupport.parkNanos(this, ns);
+                }
+                p.parked = null;
+            }
+            else if (SLOT.compareAndSet(this, p, null)) {
+                v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
+                break;
+            }
+        }
+        MATCH.setRelease(p, null);
+        p.item = null;
+        p.hash = h;
+        return v;
+    }
+
+    /**
+     * Creates a new Exchanger.
+     */
+    public Exchanger() {
+        participant = new Participant();
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted}),
+     * and then transfers the given object to it, receiving its object
+     * in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of two things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @param x the object to exchange
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x) throws InterruptedException {
+        Object v;
+        Node[] a;
+        Object item = (x == null) ? NULL_ITEM : x; // translate null args
+        if (((a = arena) != null ||
+             (v = slotExchange(item, false, 0L)) == null) &&
+            (Thread.interrupted() || // disambiguates null return
+             (v = arenaExchange(item, false, 0L)) == null))
+            throw new InterruptedException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted} or
+     * the specified waiting time elapses), and then transfers the given
+     * object to it, receiving its object in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link
+     * TimeoutException} is thrown.  If the time is less than or equal
+     * to zero, the method will not wait at all.
+     *
+     * @param x the object to exchange
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     * @throws TimeoutException if the specified waiting time elapses
+     *         before another thread enters the exchange
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x, long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        Object v;
+        Object item = (x == null) ? NULL_ITEM : x;
+        long ns = unit.toNanos(timeout);
+        if ((arena != null ||
+             (v = slotExchange(item, true, ns)) == null) &&
+            (Thread.interrupted() ||
+             (v = arenaExchange(item, true, ns)) == null))
+            throw new InterruptedException();
+        if (v == TIMED_OUT)
+            throw new TimeoutException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle BOUND;
+    private static final VarHandle SLOT;
+    private static final VarHandle MATCH;
+    private static final VarHandle AA;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
+            SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
+            MATCH = l.findVarHandle(Node.class, "match", Object.class);
+            AA = MethodHandles.arrayElementVarHandle(Node[].class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/ExecutionException.java b/android-35/java/util/concurrent/ExecutionException.java
new file mode 100644
index 0000000..71e7a71
--- /dev/null
+++ b/android-35/java/util/concurrent/ExecutionException.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when attempting to retrieve the result of a task
+ * that aborted by throwing an exception. This exception can be
+ * inspected using the {@link #getCause()} method.
+ *
+ * @see Future
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ExecutionException extends Exception {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs an {@code ExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected ExecutionException() { }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected ExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/android-35/java/util/concurrent/Executor.java b/android-35/java/util/concurrent/Executor.java
new file mode 100644
index 0000000..378cacd
--- /dev/null
+++ b/android-35/java/util/concurrent/Executor.java
@@ -0,0 +1,137 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that executes submitted {@link Runnable} tasks. This
+ * interface provides a way of decoupling task submission from the
+ * mechanics of how each task will be run, including details of thread
+ * use, scheduling, etc.  An {@code Executor} is normally used
+ * instead of explicitly creating threads. For example, rather than
+ * invoking {@code new Thread(new RunnableTask()).start()} for each
+ * of a set of tasks, you might use:
+ *
+ * <pre> {@code
+ * Executor executor = anExecutor();
+ * executor.execute(new RunnableTask1());
+ * executor.execute(new RunnableTask2());
+ * ...}</pre>
+ *
+ * However, the {@code Executor} interface does not strictly require
+ * that execution be asynchronous. In the simplest case, an executor
+ * can run the submitted task immediately in the caller's thread:
+ *
+ * <pre> {@code
+ * class DirectExecutor implements Executor {
+ *   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> {@code
+ * class ThreadPerTaskExecutor implements Executor {
+ *   public void execute(Runnable r) {
+ *     new Thread(r).start();
+ *   }
+ * }}</pre>
+ *
+ * Many {@code Executor} implementations impose some sort of
+ * limitation on how and when tasks are scheduled.  The executor below
+ * serializes the submission of tasks to a second executor,
+ * illustrating a composite executor.
+ *
+ * <pre> {@code
+ * class SerialExecutor implements Executor {
+ *   final Queue<Runnable> tasks = new ArrayDeque<>();
+ *   final Executor executor;
+ *   Runnable active;
+ *
+ *   SerialExecutor(Executor executor) {
+ *     this.executor = executor;
+ *   }
+ *
+ *   public synchronized void execute(Runnable r) {
+ *     tasks.add(() -> {
+ *       try {
+ *         r.run();
+ *       } finally {
+ *         scheduleNext();
+ *       }
+ *     });
+ *     if (active == null) {
+ *       scheduleNext();
+ *     }
+ *   }
+ *
+ *   protected synchronized void scheduleNext() {
+ *     if ((active = tasks.poll()) != null) {
+ *       executor.execute(active);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * The {@code Executor} implementations provided in this package
+ * implement {@link ExecutorService}, which is a more extensive
+ * interface.  The {@link ThreadPoolExecutor} class provides an
+ * extensible thread pool implementation. The {@link Executors} class
+ * provides convenient factory methods for these Executors.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a {@code Runnable} object to an {@code Executor}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * its execution begins, perhaps in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Executor {
+
+    /**
+     * Executes the given command at some time in the future.  The command
+     * may execute in a new thread, in a pooled thread, or in the calling
+     * thread, at the discretion of the {@code Executor} implementation.
+     *
+     * @param command the runnable task
+     * @throws RejectedExecutionException if this task cannot be
+     * accepted for execution
+     * @throws NullPointerException if command is null
+     */
+    void execute(Runnable command);
+}
diff --git a/android-35/java/util/concurrent/ExecutorCompletionService.java b/android-35/java/util/concurrent/ExecutorCompletionService.java
new file mode 100644
index 0000000..d60d3dd
--- /dev/null
+++ b/android-35/java/util/concurrent/ExecutorCompletionService.java
@@ -0,0 +1,212 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link CompletionService} that uses a supplied {@link Executor}
+ * to execute tasks.  This class arranges that submitted tasks are,
+ * upon completion, placed on a queue accessible using {@code take}.
+ * The class is lightweight enough to be suitable for transient use
+ * when processing groups of tasks.
+ *
+ * <p>
+ *
+ * <b>Usage Examples.</b>
+ *
+ * Suppose you have a set of solvers for a certain problem, each
+ * returning a value of some type {@code Result}, and would like to
+ * run them concurrently, processing the results of each of them that
+ * return a non-null value, in some method {@code use(Result r)}. You
+ * could write this as:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException, ExecutionException {
+ *   CompletionService<Result> cs
+ *       = new ExecutorCompletionService<>(e);
+ *   solvers.forEach(cs::submit);
+ *   for (int i = solvers.size(); i > 0; i--) {
+ *     Result r = cs.take().get();
+ *     if (r != null)
+ *       use(r);
+ *   }
+ * }}</pre>
+ *
+ * Suppose instead that you would like to use the first non-null result
+ * of the set of tasks, ignoring any that encounter exceptions,
+ * and cancelling all other tasks when the first one is ready:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException {
+ *   CompletionService<Result> cs
+ *       = new ExecutorCompletionService<>(e);
+ *   int n = solvers.size();
+ *   List<Future<Result>> futures = new ArrayList<>(n);
+ *   Result result = null;
+ *   try {
+ *     solvers.forEach(solver -> futures.add(cs.submit(solver)));
+ *     for (int i = n; i > 0; i--) {
+ *       try {
+ *         Result r = cs.take().get();
+ *         if (r != null) {
+ *           result = r;
+ *           break;
+ *         }
+ *       } catch (ExecutionException ignore) {}
+ *     }
+ *   } finally {
+ *     futures.forEach(future -> future.cancel(true));
+ *   }
+ *
+ *   if (result != null)
+ *     use(result);
+ * }}</pre>
+ *
+ * @since 1.5
+ */
+public class ExecutorCompletionService<V> implements CompletionService<V> {
+    private final Executor executor;
+    private final AbstractExecutorService aes;
+    private final BlockingQueue<Future<V>> completionQueue;
+
+    /**
+     * FutureTask extension to enqueue upon completion.
+     */
+    private static class QueueingFuture<V> extends FutureTask<Void> {
+        QueueingFuture(RunnableFuture<V> task,
+                       BlockingQueue<Future<V>> completionQueue) {
+            super(task, null);
+            this.task = task;
+            this.completionQueue = completionQueue;
+        }
+        private final Future<V> task;
+        private final BlockingQueue<Future<V>> completionQueue;
+        protected void done() { completionQueue.add(task); }
+    }
+
+    private RunnableFuture<V> newTaskFor(Callable<V> task) {
+        if (aes == null)
+            return new FutureTask<V>(task);
+        else
+            return aes.newTaskFor(task);
+    }
+
+    private RunnableFuture<V> newTaskFor(Runnable task, V result) {
+        if (aes == null)
+            return new FutureTask<V>(task, result);
+        else
+            return aes.newTaskFor(task, result);
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and a
+     * {@link LinkedBlockingQueue} as a completion queue.
+     *
+     * @param executor the executor to use
+     * @throws NullPointerException if executor is {@code null}
+     */
+    public ExecutorCompletionService(Executor executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and the supplied queue as its
+     * completion queue.
+     *
+     * @param executor the executor to use
+     * @param completionQueue the queue to use as the completion queue
+     *        normally one dedicated for use by this service. This
+     *        queue is treated as unbounded -- failed attempted
+     *        {@code Queue.add} operations for completed tasks cause
+     *        them not to be retrievable.
+     * @throws NullPointerException if executor or completionQueue are {@code null}
+     */
+    public ExecutorCompletionService(Executor executor,
+                                     BlockingQueue<Future<V>> completionQueue) {
+        if (executor == null || completionQueue == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = completionQueue;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<V> submit(Callable<V> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<V> submit(Runnable task, V result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task, result);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    public Future<V> take() throws InterruptedException {
+        return completionQueue.take();
+    }
+
+    public Future<V> poll() {
+        return completionQueue.poll();
+    }
+
+    public Future<V> poll(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return completionQueue.poll(timeout, unit);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/ExecutorService.java b/android-35/java/util/concurrent/ExecutorService.java
new file mode 100644
index 0000000..8d7ec6d
--- /dev/null
+++ b/android-35/java/util/concurrent/ExecutorService.java
@@ -0,0 +1,360 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.List;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link Executor} that provides methods to manage termination and
+ * methods that can produce a {@link Future} for tracking progress of
+ * one or more asynchronous tasks.
+ *
+ * <p>An {@code ExecutorService} can be shut down, which will cause
+ * it to reject new tasks.  Two different methods are provided for
+ * shutting down an {@code ExecutorService}. The {@link #shutdown}
+ * method will allow previously submitted tasks to execute before
+ * terminating, while the {@link #shutdownNow} method prevents waiting
+ * tasks from starting and attempts to stop currently executing tasks.
+ * Upon termination, an executor has no tasks actively executing, no
+ * tasks awaiting execution, and no new tasks can be submitted.  An
+ * unused {@code ExecutorService} should be shut down to allow
+ * reclamation of its resources.
+ *
+ * <p>Method {@code submit} extends base method {@link
+ * Executor#execute(Runnable)} by creating and returning a {@link Future}
+ * that can be used to cancel execution and/or wait for completion.
+ * Methods {@code invokeAny} and {@code invokeAll} perform the most
+ * commonly useful forms of bulk execution, executing a collection of
+ * tasks and then waiting for at least one, or all, to
+ * complete. (Class {@link ExecutorCompletionService} can be used to
+ * write customized variants of these methods.)
+ *
+ * <p>The {@link Executors} class provides factory methods for the
+ * executor services provided in this package.
+ *
+ * <h2>Usage Examples</h2>
+ *
+ * Here is a sketch of a network service in which threads in a thread
+ * pool service incoming requests. It uses the preconfigured {@link
+ * Executors#newFixedThreadPool} factory method:
+ *
+ * <pre> {@code
+ * class NetworkService implements Runnable {
+ *   private final ServerSocket serverSocket;
+ *   private final ExecutorService pool;
+ *
+ *   public NetworkService(int port, int poolSize)
+ *       throws IOException {
+ *     serverSocket = new ServerSocket(port);
+ *     pool = Executors.newFixedThreadPool(poolSize);
+ *   }
+ *
+ *   public void run() { // run the service
+ *     try {
+ *       for (;;) {
+ *         pool.execute(new Handler(serverSocket.accept()));
+ *       }
+ *     } catch (IOException ex) {
+ *       pool.shutdown();
+ *     }
+ *   }
+ * }
+ *
+ * class Handler implements Runnable {
+ *   private final Socket socket;
+ *   Handler(Socket socket) { this.socket = socket; }
+ *   public void run() {
+ *     // read and service request on socket
+ *   }
+ * }}</pre>
+ *
+ * The following method shuts down an {@code ExecutorService} in two phases,
+ * first by calling {@code shutdown} to reject incoming tasks, and then
+ * calling {@code shutdownNow}, if necessary, to cancel any lingering tasks:
+ *
+ * <pre> {@code
+ * void shutdownAndAwaitTermination(ExecutorService pool) {
+ *   pool.shutdown(); // Disable new tasks from being submitted
+ *   try {
+ *     // Wait a while for existing tasks to terminate
+ *     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ *       pool.shutdownNow(); // Cancel currently executing tasks
+ *       // Wait a while for tasks to respond to being cancelled
+ *       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ *           System.err.println("Pool did not terminate");
+ *     }
+ *   } catch (InterruptedException ex) {
+ *     // (Re-)Cancel if current thread also interrupted
+ *     pool.shutdownNow();
+ *     // Preserve interrupt status
+ *     Thread.currentThread().interrupt();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to the
+ * submission of a {@code Runnable} or {@code Callable} task to an
+ * {@code ExecutorService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * any actions taken by that task, which in turn <i>happen-before</i> the
+ * result is retrieved via {@code Future.get()}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ExecutorService extends Executor {
+
+    /**
+     * 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.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    void shutdown();
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  For example, typical
+     * implementations will cancel via {@link Thread#interrupt}, so any
+     * task that fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution
+     */
+    List<Runnable> shutdownNow();
+
+    /**
+     * Returns {@code true} if this executor has been shut down.
+     *
+     * @return {@code true} if this executor has been shut down
+     */
+    boolean isShutdown();
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     * Note that {@code isTerminated} is never {@code true} unless
+     * either {@code shutdown} or {@code shutdownNow} was called first.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    boolean isTerminated();
+
+    /**
+     * 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
+     */
+    boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Submits a value-returning task for execution and returns a
+     * Future representing the pending results of the task. The
+     * Future's {@code get} method will return the task's result upon
+     * successful completion.
+     *
+     * <p>
+     * If you would like to immediately block waiting
+     * for a task, you can use constructions of the form
+     * {@code result = exec.submit(aCallable).get();}
+     *
+     * <p>Note: The {@link Executors} class includes a set of methods
+     * that can convert some other common closure-like objects,
+     * for example, {@link java.security.PrivilegedAction} to
+     * {@link Callable} form so they can be submitted.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Callable<T> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return the given result upon successful completion.
+     *
+     * @param task the task to submit
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Runnable task, T result);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return {@code null} upon <em>successful</em> completion.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<?> submit(Runnable task);
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results when all complete.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list, each of which has completed
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks or any of its elements are {@code null}
+     * @throws RejectedExecutionException if any task cannot be
+     *         scheduled for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results
+     * when all complete or the timeout expires, whichever happens first.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Upon return, tasks that have not completed are cancelled.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list. If the operation did not time out,
+     *         each task will have completed. If it did time out, some
+     *         of these tasks will not have completed.
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks, any of its elements, or
+     *         unit are {@code null}
+     * @throws RejectedExecutionException if any task cannot be scheduled
+     *         for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                  long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do. Upon normal or exceptional return,
+     * tasks that have not completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks or any element task
+     *         subject to execution is {@code null}
+     * @throws IllegalArgumentException if tasks is empty
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do before the given timeout elapses.
+     * Upon normal or exceptional return, tasks that have not
+     * completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks, or unit, or any element
+     *         task subject to execution is {@code null}
+     * @throws TimeoutException if the given timeout elapses before
+     *         any task successfully completes
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                    long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/android-35/java/util/concurrent/Executors.java b/android-35/java/util/concurrent/Executors.java
new file mode 100644
index 0000000..fc7a9b7
--- /dev/null
+++ b/android-35/java/util/concurrent/Executors.java
@@ -0,0 +1,785 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.lang.ref.Reference.reachabilityFence;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.security.util.SecurityConstants;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * Factory and utility methods for {@link Executor}, {@link
+ * ExecutorService}, {@link ScheduledExecutorService}, {@link
+ * ThreadFactory}, and {@link Callable} classes defined in this
+ * package. This class supports the following kinds of methods:
+ *
+ * <ul>
+ *   <li>Methods that create and return an {@link ExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a {@link ScheduledExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a "wrapped" ExecutorService, that
+ *       disables reconfiguration by making implementation-specific methods
+ *       inaccessible.
+ *   <li>Methods that create and return a {@link ThreadFactory}
+ *       that sets newly created threads to a known state.
+ *   <li>Methods that create and return a {@link Callable}
+ *       out of other closure-like forms, so they can be used
+ *       in execution methods requiring {@code Callable}.
+ * </ul>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Executors {
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue.  At any point, at most
+     * {@code nThreads} threads will be active processing tasks.
+     * If additional tasks are submitted when all threads are active,
+     * they will wait in the queue until a thread is available.
+     * If any thread terminates due to a failure during execution
+     * prior to shutdown, a new one will take its place if needed to
+     * execute subsequent tasks.  The threads in the pool will exist
+     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that maintains enough threads to support
+     * the given parallelism level, and may use multiple queues to
+     * reduce contention. The parallelism level corresponds to the
+     * maximum number of threads actively engaged in, or available to
+     * engage in, task processing. The actual number of threads may
+     * grow and shrink dynamically. A work-stealing pool makes no
+     * guarantees about the order in which submitted tasks are
+     * executed.
+     *
+     * @param parallelism the targeted parallelism level
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code parallelism <= 0}
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool(int parallelism) {
+        return new ForkJoinPool
+            (parallelism,
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a work-stealing thread pool using the number of
+     * {@linkplain Runtime#availableProcessors available processors}
+     * as its target parallelism level.
+     *
+     * @return the newly created thread pool
+     * @see #newWorkStealingPool(int)
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool() {
+        return new ForkJoinPool
+            (Runtime.getRuntime().availableProcessors(),
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue, using the provided
+     * ThreadFactory to create new threads when needed.  At any point,
+     * at most {@code nThreads} threads will be active processing
+     * tasks.  If additional tasks are submitted when all threads are
+     * active, they will wait in the queue until a thread is
+     * available.  If any thread terminates due to a failure during
+     * execution prior to shutdown, a new one will take its place if
+     * needed to execute subsequent tasks.  The threads in the pool will
+     * exist until it is explicitly {@link ExecutorService#shutdown
+     * shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue. (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newFixedThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     *
+     * @return the newly created single-threaded Executor
+     */
+    public static ExecutorService newSingleThreadExecutor() {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>()));
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue, and uses the provided ThreadFactory to
+     * create a new thread when needed. Unlike the otherwise
+     * equivalent {@code newFixedThreadPool(1, threadFactory)} the
+     * returned executor is guaranteed not to be reconfigurable to use
+     * additional threads.
+     *
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created single-threaded Executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>(),
+                                    threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available.  These pools will typically improve the performance
+     * of programs that execute many short-lived asynchronous tasks.
+     * Calls to {@code execute} will reuse previously constructed
+     * threads if available. If no existing thread is available, a new
+     * thread will be created and added to the pool. Threads that have
+     * not been used for sixty seconds are terminated and removed from
+     * the cache. Thus, a pool that remains idle for long enough will
+     * not consume any resources. Note that pools with similar
+     * properties but different details (for example, timeout parameters)
+     * may be created using {@link ThreadPoolExecutor} constructors.
+     *
+     * @return the newly created thread pool
+     */
+    public static ExecutorService newCachedThreadPool() {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available, and uses the provided
+     * ThreadFactory to create new threads when needed.
+     *
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.
+     * (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newScheduledThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     *
+     * @return the newly created scheduled executor
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1));
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.  (Note
+     * however that if this single thread terminates due to a failure
+     * during execution prior to shutdown, a new one will take its
+     * place if needed to execute subsequent tasks.)  Tasks are
+     * guaranteed to execute sequentially, and no more than one task
+     * will be active at any given time. Unlike the otherwise
+     * equivalent {@code newScheduledThreadPool(1, threadFactory)}
+     * the returned executor is guaranteed not to be reconfigurable to
+     * use additional threads.
+     *
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created scheduled executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1, threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @return the newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
+        return new ScheduledThreadPoolExecutor(corePoolSize);
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @param threadFactory the factory to use when the executor
+     * creates a new thread
+     * @return the newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(
+            int corePoolSize, ThreadFactory threadFactory) {
+        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ExecutorService} methods to the given executor, but not any
+     * other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return an {@code ExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedExecutorService(executor);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ScheduledExecutorService} methods to the given executor, but
+     * not any other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return a {@code ScheduledExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedScheduledExecutorService(executor);
+    }
+
+    // Android-changed: Removed references to SecurityManager from javadoc.
+    /**
+     * 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}. Each new
+     * thread is created as a non-daemon thread with priority set to
+     * the smaller of {@code Thread.NORM_PRIORITY} and the maximum
+     * priority permitted in the thread group.  New threads have names
+     * accessible via {@link Thread#getName} of
+     * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
+     * number of this factory, and <em>M</em> is the sequence number
+     * of the thread created by this factory.
+     * @return a thread factory
+     */
+    public static ThreadFactory defaultThreadFactory() {
+        return new DefaultThreadFactory();
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     *
+     * @deprecated This method is only useful in conjunction with
+     *       {@linkplain SecurityManager the Security Manager}, which is
+     *       deprecated and subject to removal in a future release.
+     *       Consequently, this method is also deprecated and subject to
+     *       removal. There is no replacement for the Security Manager or this
+     *       method.
+     */
+    @Deprecated(since="17", forRemoval=true)
+    public static ThreadFactory privilegedThreadFactory() {
+        return new PrivilegedThreadFactory();
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns the given result.  This
+     * can be useful when applying methods requiring a
+     * {@code Callable} to an otherwise resultless action.
+     * @param task the task to run
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static <T> Callable<T> callable(Runnable task, T result) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<T>(task, result);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns {@code null}.
+     * @param task the task to run
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static Callable<Object> callable(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<Object>(task, null);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged action and returns its result.
+     * @param action the privileged action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() { return action.run(); }};
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged exception action and returns
+     * its result.
+     * @param action the privileged exception action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() throws Exception { return action.run(); }};
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     *
+     * @deprecated This method is only useful in conjunction with
+     *       {@linkplain SecurityManager the Security Manager}, which is
+     *       deprecated and subject to removal in a future release.
+     *       Consequently, this method is also deprecated and subject to
+     *       removal. There is no replacement for the Security Manager or this
+     *       method.
+     */
+    @Deprecated(since="17", forRemoval=true)
+    public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallable<T>(callable);
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     *
+     * @deprecated This method is only useful in conjunction with
+     *       {@linkplain SecurityManager the Security Manager}, which is
+     *       deprecated and subject to removal in a future release.
+     *       Consequently, this method is also deprecated and subject to
+     *       removal. There is no replacement for the Security Manager or this
+     *       method.
+     */
+    @Deprecated(since="17", forRemoval=true)
+    public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
+    }
+
+    // Non-public classes supporting the public methods
+
+    /**
+     * A callable that runs given task and returns given result.
+     */
+    private static final class RunnableAdapter<T> implements Callable<T> {
+        private final Runnable task;
+        private final T result;
+        RunnableAdapter(Runnable task, T result) {
+            this.task = task;
+            this.result = result;
+        }
+        public T call() {
+            task.run();
+            return result;
+        }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings.
+     */
+    private static final class PrivilegedCallable<T> implements Callable<T> {
+        final Callable<T> task;
+        @SuppressWarnings("removal")
+        final AccessControlContext acc;
+
+        @SuppressWarnings("removal")
+        PrivilegedCallable(Callable<T> task) {
+            this.task = task;
+            this.acc = AccessController.getContext();
+        }
+
+        @SuppressWarnings("removal")
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            return task.call();
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings and
+     * current ClassLoader.
+     */
+    private static final class PrivilegedCallableUsingCurrentClassLoader<T>
+            implements Callable<T> {
+        final Callable<T> task;
+        @SuppressWarnings("removal")
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        @SuppressWarnings("removal")
+        PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            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"));
+            }
+            */
+            this.task = task;
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        @SuppressWarnings("removal")
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            Thread t = Thread.currentThread();
+                            ClassLoader cl = t.getContextClassLoader();
+                            if (ccl == cl) {
+                                return task.call();
+                            } else {
+                                t.setContextClassLoader(ccl);
+                                try {
+                                    return task.call();
+                                } finally {
+                                    t.setContextClassLoader(cl);
+                                }
+                            }
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
+    }
+
+    /**
+     * The default thread factory.
+     */
+    private static class DefaultThreadFactory implements ThreadFactory {
+        private static final AtomicInteger poolNumber = new AtomicInteger(1);
+        private final ThreadGroup group;
+        private final AtomicInteger threadNumber = new AtomicInteger(1);
+        private final String namePrefix;
+
+        DefaultThreadFactory() {
+            @SuppressWarnings("removal")
+            SecurityManager s = System.getSecurityManager();
+            group = (s != null) ? s.getThreadGroup() :
+                                  Thread.currentThread().getThreadGroup();
+            namePrefix = "pool-" +
+                          poolNumber.getAndIncrement() +
+                         "-thread-";
+        }
+
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r,
+                                  namePrefix + threadNumber.getAndIncrement(),
+                                  0);
+            if (t.isDaemon())
+                t.setDaemon(false);
+            if (t.getPriority() != Thread.NORM_PRIORITY)
+                t.setPriority(Thread.NORM_PRIORITY);
+            return t;
+        }
+    }
+
+    /**
+     * Thread factory capturing access control context and class loader.
+     */
+    private static class PrivilegedThreadFactory extends DefaultThreadFactory {
+        @SuppressWarnings("removal")
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        @SuppressWarnings("removal")
+        PrivilegedThreadFactory() {
+            super();
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            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"));
+            }
+            */
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        public Thread newThread(final Runnable r) {
+            return super.newThread(new Runnable() {
+                @SuppressWarnings("removal")
+                public void run() {
+                    AccessController.doPrivileged(new PrivilegedAction<>() {
+                        public Void run() {
+                            Thread.currentThread().setContextClassLoader(ccl);
+                            r.run();
+                            return null;
+                        }
+                    }, acc);
+                }
+            });
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ExecutorService methods
+     * of an ExecutorService implementation.
+     */
+    private static class DelegatedExecutorService
+            implements ExecutorService {
+        // Android-added: @ReachabilitySensitive
+        // Needed for FinalizableDelegatedExecutorService below.
+        @ReachabilitySensitive
+        private final ExecutorService e;
+        DelegatedExecutorService(ExecutorService executor) { e = executor; }
+        public void execute(Runnable command) {
+            try {
+                e.execute(command);
+            } finally { reachabilityFence(this); }
+        }
+        public void shutdown() { e.shutdown(); }
+        public List<Runnable> shutdownNow() {
+            try {
+                return e.shutdownNow();
+            } finally { reachabilityFence(this); }
+        }
+        public boolean isShutdown() {
+            try {
+                return e.isShutdown();
+            } finally { reachabilityFence(this); }
+        }
+        public boolean isTerminated() {
+            try {
+                return e.isTerminated();
+            } finally { reachabilityFence(this); }
+        }
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+            throws InterruptedException {
+            try {
+                return e.awaitTermination(timeout, unit);
+            } finally { reachabilityFence(this); }
+        }
+        public Future<?> submit(Runnable task) {
+            try {
+                return e.submit(task);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> Future<T> submit(Callable<T> task) {
+            try {
+                return e.submit(task);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> Future<T> submit(Runnable task, T result) {
+            try {
+                return e.submit(task, result);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException {
+            try {
+                return e.invokeAll(tasks);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                             long timeout, TimeUnit unit)
+            throws InterruptedException {
+            try {
+                return e.invokeAll(tasks, timeout, unit);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException, ExecutionException {
+            try {
+                return e.invokeAny(tasks);
+            } finally { reachabilityFence(this); }
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                               long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException {
+            try {
+                return e.invokeAny(tasks, timeout, unit);
+            } finally { reachabilityFence(this); }
+        }
+    }
+
+    private static class FinalizableDelegatedExecutorService
+            extends DelegatedExecutorService {
+        FinalizableDelegatedExecutorService(ExecutorService executor) {
+            super(executor);
+        }
+        @SuppressWarnings("deprecation")
+        protected void finalize() {
+            super.shutdown();
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ScheduledExecutorService
+     * methods of a ScheduledExecutorService implementation.
+     */
+    private static class DelegatedScheduledExecutorService
+            extends DelegatedExecutorService
+            implements ScheduledExecutorService {
+        private final ScheduledExecutorService e;
+        DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
+            super(executor);
+            e = executor;
+        }
+        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+            return e.schedule(command, delay, unit);
+        }
+        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+            return e.schedule(callable, delay, unit);
+        }
+        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+            return e.scheduleAtFixedRate(command, initialDelay, period, unit);
+        }
+        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+            return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+        }
+    }
+
+    /** Cannot instantiate. */
+    private Executors() {}
+}
diff --git a/android-35/java/util/concurrent/Flow.java b/android-35/java/util/concurrent/Flow.java
new file mode 100644
index 0000000..727a507
--- /dev/null
+++ b/android-35/java/util/concurrent/Flow.java
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// Android-changed: Remove reference to SubmissionPublisher class (not present on Android).
+/**
+ * Interrelated interfaces and static methods for establishing
+ * flow-controlled components in which {@link Publisher Publishers}
+ * produce items consumed by one or more {@link Subscriber
+ * Subscribers}, each managed by a {@link Subscription
+ * Subscription}.
+ *
+ * <p>These interfaces correspond to the <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * specification.  They apply in both concurrent and distributed
+ * asynchronous settings: All (seven) methods are defined in {@code
+ * void} "one-way" message style. Communication relies on a simple form
+ * of flow control (method {@link Subscription#request}) that can be
+ * used to avoid resource management problems that may otherwise occur
+ * in "push" based systems.
+ *
+ * <p><b>Examples.</b> A {@link Publisher} usually defines its own
+ * {@link Subscription} implementation; constructing one in method
+ * {@code subscribe} and issuing it to the calling {@link
+ * Subscriber}. It publishes items to the subscriber asynchronously,
+ * normally using an {@link Executor}.  For example, here is a very
+ * simple publisher that only issues (when requested) a single {@code
+ * TRUE} item to a single subscriber.  Because the subscriber receives
+ * only a single item, this class does not use buffering and ordering
+ * control required in most implementations.
+ *
+ * <pre> {@code
+ * class OneShotPublisher implements Publisher<Boolean> {
+ *   private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
+ *   private boolean subscribed; // true after first subscribe
+ *   public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
+ *     if (subscribed)
+ *       subscriber.onError(new IllegalStateException()); // only one allowed
+ *     else {
+ *       subscribed = true;
+ *       subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
+ *     }
+ *   }
+ *   static class OneShotSubscription implements Subscription {
+ *     private final Subscriber<? super Boolean> subscriber;
+ *     private final ExecutorService executor;
+ *     private Future<?> future; // to allow cancellation
+ *     private boolean completed;
+ *     OneShotSubscription(Subscriber<? super Boolean> subscriber,
+ *                         ExecutorService executor) {
+ *       this.subscriber = subscriber;
+ *       this.executor = executor;
+ *     }
+ *     public synchronized void request(long n) {
+ *       if (!completed) {
+ *         completed = true;
+ *         if (n <= 0) {
+ *           IllegalArgumentException ex = new IllegalArgumentException();
+ *           executor.execute(() -> subscriber.onError(ex));
+ *         } else {
+ *           future = executor.submit(() -> {
+ *             subscriber.onNext(Boolean.TRUE);
+ *             subscriber.onComplete();
+ *           });
+ *         }
+ *       }
+ *     }
+ *     public synchronized void cancel() {
+ *       completed = true;
+ *       if (future != null) future.cancel(false);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>A {@link Subscriber} arranges that items be requested and
+ * processed.  Items (invocations of {@link Subscriber#onNext}) are
+ * not issued unless requested, but multiple items may be requested.
+ * Many Subscriber implementations can arrange this in the style of
+ * the following example, where a buffer size of 1 single-steps, and
+ * larger sizes usually allow for more efficient overlapped processing
+ * with less communication; for example with a value of 64, this keeps
+ * total outstanding requests between 32 and 64.
+ * Because Subscriber method invocations for a given {@link
+ * Subscription} are strictly ordered, there is no need for these
+ * methods to use locks or volatiles unless a Subscriber maintains
+ * multiple Subscriptions (in which case it is better to instead
+ * define multiple Subscribers, each with its own Subscription).
+ *
+ * <pre> {@code
+ * class SampleSubscriber<T> implements Subscriber<T> {
+ *   final Consumer<? super T> consumer;
+ *   Subscription subscription;
+ *   final long bufferSize;
+ *   long count;
+ *   SampleSubscriber(long bufferSize, Consumer<? super T> consumer) {
+ *     this.bufferSize = bufferSize;
+ *     this.consumer = consumer;
+ *   }
+ *   public void onSubscribe(Subscription subscription) {
+ *     long initialRequestSize = bufferSize;
+ *     count = bufferSize - bufferSize / 2; // re-request when half consumed
+ *     (this.subscription = subscription).request(initialRequestSize);
+ *   }
+ *   public void onNext(T item) {
+ *     if (--count <= 0)
+ *       subscription.request(count = bufferSize - bufferSize / 2);
+ *     consumer.accept(item);
+ *   }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ * }}</pre>
+ *
+ * <p>The default value of {@link #defaultBufferSize} may provide a
+ * useful starting point for choosing request sizes and capacities in
+ * Flow components based on expected rates, resources, and usages.
+ * Or, when flow control is never needed, a subscriber may initially
+ * request an effectively unbounded number of items, as in:
+ *
+ * <pre> {@code
+ * class UnboundedSubscriber<T> implements Subscriber<T> {
+ *   public void onSubscribe(Subscription subscription) {
+ *     subscription.request(Long.MAX_VALUE); // effectively unbounded
+ *   }
+ *   public void onNext(T item) { use(item); }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ *   void use(T item) { ... }
+ * }}</pre>
+ *
+ * @author Doug Lea
+ * @since 9
+ */
+public final class Flow {
+
+    private Flow() {} // uninstantiable
+
+    /**
+     * A producer of items (and related control messages) received by
+     * Subscribers.  Each current {@link Subscriber} receives the same
+     * items (via method {@code onNext}) in the same order, unless
+     * drops or errors are encountered. If a Publisher encounters an
+     * error that does not allow items to be issued to a Subscriber,
+     * that Subscriber receives {@code onError}, and then receives no
+     * further messages.  Otherwise, when it is known that no further
+     * messages will be issued to it, a subscriber receives {@code
+     * onComplete}.  Publishers ensure that Subscriber method
+     * invocations for each subscription are strictly ordered in <a
+     * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * order.
+     *
+     * <p>Publishers may vary in policy about whether drops (failures
+     * to issue an item because of resource limitations) are treated
+     * as unrecoverable errors.  Publishers may also vary about
+     * whether Subscribers receive items that were produced or
+     * available before they subscribed.
+     *
+     * @param <T> the published item type
+     */
+    @FunctionalInterface
+    public static interface Publisher<T> {
+        /**
+         * Adds the given Subscriber if possible.  If already
+         * subscribed, or the attempt to subscribe fails due to policy
+         * violations or errors, the Subscriber's {@code onError}
+         * method is invoked with an {@link IllegalStateException}.
+         * Otherwise, the Subscriber's {@code onSubscribe} method is
+         * invoked with a new {@link Subscription}.  Subscribers may
+         * enable receiving items by invoking the {@code request}
+         * method of this Subscription, and may unsubscribe by
+         * invoking its {@code cancel} method.
+         *
+         * @param subscriber the subscriber
+         * @throws NullPointerException if subscriber is null
+         */
+        public void subscribe(Subscriber<? super T> subscriber);
+    }
+
+    /**
+     * A receiver of messages.  The methods in this interface are
+     * invoked in strict sequential order for each {@link
+     * Subscription}.
+     *
+     * @param <T> the subscribed item type
+     */
+    public static interface Subscriber<T> {
+        /**
+         * Method invoked prior to invoking any other Subscriber
+         * methods for the given Subscription. If this method throws
+         * an exception, resulting behavior is not guaranteed, but may
+         * cause the Subscription not to be established or to be cancelled.
+         *
+         * <p>Typically, implementations of this method invoke {@code
+         * subscription.request} to enable receiving items.
+         *
+         * @param subscription a new subscription
+         */
+        public void onSubscribe(Subscription subscription);
+
+        /**
+         * Method invoked with a Subscription's next item.  If this
+         * method throws an exception, resulting behavior is not
+         * guaranteed, but may cause the Subscription to be cancelled.
+         *
+         * @param item the item
+         */
+        public void onNext(T item);
+
+        /**
+         * Method invoked upon an unrecoverable error encountered by a
+         * Publisher or Subscription, after which no other Subscriber
+         * methods are invoked by the Subscription.  If this method
+         * itself throws an exception, resulting behavior is
+         * undefined.
+         *
+         * @param throwable the exception
+         */
+        public void onError(Throwable throwable);
+
+        /**
+         * Method invoked when it is known that no additional
+         * Subscriber method invocations will occur for a Subscription
+         * that is not already terminated by error, after which no
+         * other Subscriber methods are invoked by the Subscription.
+         * If this method throws an exception, resulting behavior is
+         * undefined.
+         */
+        public void onComplete();
+    }
+
+    /**
+     * Message control linking a {@link Publisher} and {@link
+     * Subscriber}.  Subscribers receive items only when requested,
+     * and may cancel at any time. The methods in this interface are
+     * intended to be invoked only by their Subscribers; usages in
+     * other contexts have undefined effects.
+     */
+    public static interface Subscription {
+        /**
+         * Adds the given number {@code n} of items to the current
+         * unfulfilled demand for this subscription.  If {@code n} is
+         * less than or equal to zero, the Subscriber will receive an
+         * {@code onError} signal with an {@link
+         * IllegalArgumentException} argument.  Otherwise, the
+         * Subscriber will receive up to {@code n} additional {@code
+         * onNext} invocations (or fewer if terminated).
+         *
+         * @param n the increment of demand; a value of {@code
+         * Long.MAX_VALUE} may be considered as effectively unbounded
+         */
+        public void request(long n);
+
+        /**
+         * Causes the Subscriber to (eventually) stop receiving
+         * messages.  Implementation is best-effort -- additional
+         * messages may be received after invoking this method.
+         * A cancelled subscription need not ever receive an
+         * {@code onComplete} or {@code onError} signal.
+         */
+        public void cancel();
+    }
+
+    /**
+     * A component that acts as both a Subscriber and Publisher.
+     *
+     * @param <T> the subscribed item type
+     * @param <R> the published item type
+     */
+    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
+    }
+
+    static final int DEFAULT_BUFFER_SIZE = 256;
+
+    /**
+     * Returns a default value for Publisher or Subscriber buffering,
+     * that may be used in the absence of other constraints.
+     *
+     * @implNote
+     * The current value returned is 256.
+     *
+     * @return the buffer size value
+     */
+    public static int defaultBufferSize() {
+        return DEFAULT_BUFFER_SIZE;
+    }
+
+}
diff --git a/android-35/java/util/concurrent/ForkJoinPool.java b/android-35/java/util/concurrent/ForkJoinPool.java
new file mode 100644
index 0000000..f73af23
--- /dev/null
+++ b/android-35/java/util/concurrent/ForkJoinPool.java
@@ -0,0 +1,3518 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
+
+// Android-changed: Substituted @systemProperty tag with @code.
+/**
+ * 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 tasks submitted to the pool and/or 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), as well as when many small
+ * tasks are submitted to the pool from external clients.  Especially
+ * 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. All worker threads are initialized
+ * with {@link Thread#isDaemon} set {@code true}.
+ *
+ * <p>A static {@link #commonPool()} is available and appropriate for
+ * most applications. The common pool is used by any ForkJoinTask that
+ * is not explicitly submitted to a specified pool. Using the common
+ * pool normally reduces resource usage (its threads are slowly
+ * reclaimed during periods of non-use, and reinstated upon subsequent
+ * use).
+ *
+ * <p>For applications that require separate or custom pools, a {@code
+ * ForkJoinPool} may be 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
+ * I/O or other unmanaged synchronization. The nested {@link
+ * ManagedBlocker} interface enables extension of the kinds of
+ * synchronization accommodated. The default policies may be
+ * overridden using a constructor with parameters corresponding to
+ * those documented in class {@link ThreadPoolExecutor}.
+ *
+ * <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 primarily 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 instead
+ * use the within-computation forms listed in the table unless using
+ * async event-style tasks that are not usually joined, in which case
+ * there is little difference among choice of methods.
+ *
+ * <table class="plain">
+ * <caption>Summary of task execution methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <th scope="col"> Call from non-fork/join clients</th>
+ *    <th scope="col"> Call from within fork/join computations</th>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left"> Arrange async execution</th>
+ *    <td> {@link #execute(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left"> Await and obtain result</th>
+ *    <td> {@link #invoke(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#invoke}</td>
+ *  </tr>
+ *  <tr>
+ *    <th scope="row" style="text-align:left"> Arrange exec and obtain Future</th>
+ *    <td> {@link #submit(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>The parameters used to construct the common pool may be controlled by
+ * setting the following {@linkplain System#getProperty system properties}:
+ * <ul>
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
+ * - the parallelism level, a non-negative integer
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}.
+ * The {@linkplain ClassLoader#getSystemClassLoader() system class loader}
+ * is used to load this class.
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
+ * - the maximum number of allowed extra threads to maintain target
+ * parallelism (default 256).
+ * </ul>
+ * If no thread factory is supplied via a system property, then the
+ * common pool uses a factory that uses the system class loader as the
+ * {@linkplain Thread#getContextClassLoader() thread context class loader}.
+ * In addition, if a {@link SecurityManager} is present, then
+ * the common pool uses a factory supplying threads that have no
+ * {@link Permissions} enabled.
+ *
+ * Upon any error in establishing these settings, default parameters
+ * are used. It is possible to disable or limit the use of threads in
+ * the common pool by setting the parallelism property to zero, and/or
+ * using a factory that may return {@code null}. However doing so may
+ * cause unjoined tasks to never be executed.
+ *
+ * <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
+ * @author Doug Lea
+ */
[email protected]
+public class ForkJoinPool extends AbstractExecutorService {
+
+    // Android-changed: Substituted time reference with Android API version reference.
+    /*
+     * Implementation Overview
+     *
+     * This class and its nested classes provide the main
+     * functionality and control for a set of worker threads:
+     * Submissions from non-FJ threads enter into submission queues.
+     * Workers take these tasks and typically split them into subtasks
+     * that may be stolen by other workers. Work-stealing based on
+     * randomized scans generally leads to better throughput than
+     * "work dealing" in which producers assign tasks to idle threads,
+     * in part because threads that have finished other tasks before
+     * the signalled thread wakes up (which can be a long time) can
+     * take the task instead.  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
+     * queues.  This framework began as vehicle for supporting
+     * tree-structured parallelism using work-stealing.  Over time,
+     * its scalability advantages led to extensions and changes to
+     * better support more diverse usage contexts.  Because most
+     * internal methods and nested classes are interrelated, their
+     * main rationale and descriptions are presented here; individual
+     * methods and nested classes contain only brief comments about
+     * details.
+     *
+     * WorkQueues
+     * ==========
+     *
+     * Most operations occur within work-stealing queues (in nested
+     * class WorkQueue).  These are special forms of Deques that
+     * support only three of the four possible end-operations -- push,
+     * pop, and poll (aka steal), under the further constraints that
+     * push and pop are called only from the owning thread (or, as
+     * extended here, under a lock), while poll 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 poll (steal) from being on the indices
+     * ("base" and "top") to the slots themselves.
+     *
+     * Adding tasks then takes the form of a classic array push(task)
+     * in a circular buffer:
+     *    q.array[q.top++ % length] = task;
+     *
+     * The actual code needs to null-check and size-check the array,
+     * uses masking, not mod, for indexing a power-of-two-sized array,
+     * enforces memory ordering, supports resizing, and possibly
+     * signals waiting workers to start scanning -- see below.
+     *
+     * The pop operation (always performed by owner) is of the form:
+     *   if ((task = getAndSet(q.array, (q.top-1) % length, null)) != null)
+     *        decrement top and return task;
+     * If this fails, the queue is empty.
+     *
+     * The poll operation by another stealer thread is, basically:
+     *   if (CAS nonnull task at q.array[q.base % length] to null)
+     *       increment base and return task;
+     *
+     * This may fail due to contention, and may be retried.
+     * Implementations must ensure a consistent snapshot of the base
+     * index and the task (by looping or trying elsewhere) before
+     * trying CAS.  There isn't actually a method of this form,
+     * because failure due to inconsistency or contention is handled
+     * in different ways in different contexts, normally by first
+     * trying other queues. (For the most straightforward example, see
+     * method pollScan.) There are further variants for cases
+     * requiring inspection of elements before extracting them, so
+     * must interleave these with variants of this code.  Also, a more
+     * efficient version (nextLocalTask) is used for polls by owners.
+     * It avoids some overhead because the queue cannot be growing
+     * during call.
+     *
+     * Memory ordering.  See "Correct and Efficient Work-Stealing for
+     * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
+     * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
+     * analysis of memory ordering requirements in work-stealing
+     * algorithms similar to the one used here.  Inserting and
+     * extracting tasks in array slots via volatile or atomic accesses
+     * or explicit fences provides primary synchronization.
+     *
+     * Operations on deque elements require reads and writes of both
+     * indices and slots. When possible, we allow these to occur in
+     * any order.  Because the base and top indices (along with other
+     * pool or array fields accessed in many methods) only imprecisely
+     * guide where to extract from, we let accesses other than the
+     * element getAndSet/CAS/setVolatile appear in any order, using
+     * plain mode. But we must still preface some methods (mainly
+     * those that may be accessed externally) with an acquireFence to
+     * avoid unbounded staleness. This is equivalent to acting as if
+     * callers use an acquiring read of the reference to the pool or
+     * queue when invoking the method, even when they do not. We use
+     * explicit acquiring reads (getSlot) rather than plain array
+     * access when acquire mode is required but not otherwise ensured
+     * by context. To reduce stalls by other stealers, we encourage
+     * timely writes to the base index by immediately following
+     * updates with a write of a volatile field that must be updated
+     * anyway, or an Opaque-mode write if there is no such
+     * opportunity.
+     *
+     * Because indices and slot contents cannot always be consistent,
+     * the emptiness check base == top is only quiescently accurate
+     * (and so used where this suffices). Otherwise, it may err on the
+     * side of possibly making the queue appear nonempty when a push,
+     * pop, or poll have not fully committed, or making it appear
+     * empty when an update of top or base has not yet been seen.
+     * Similarly, the check in push for the queue array being full may
+     * trigger when not completely full, causing a resize earlier than
+     * required.
+     *
+     * Mainly because of these potential inconsistencies among slots
+     * vs indices, the poll operation, considered individually, is not
+     * wait-free. One thief cannot successfully continue until another
+     * in-progress one (or, if previously empty, a push) visibly
+     * completes.  This can stall threads when required to consume
+     * from a given queue (which may spin).  However, in the
+     * aggregate, we ensure probabilistic non-blockingness at least
+     * until checking quiescence (which is intrinsically blocking):
+     * If an attempted steal fails, a scanning thief chooses a
+     * different victim target to try next. So, in order for one thief
+     * to progress, it suffices for any in-progress poll or new push
+     * on any empty queue to complete. The worst cases occur when many
+     * threads are looking for tasks being produced by a stalled
+     * producer.
+     *
+     * This approach also enables support of a user mode in which
+     * local task processing is in FIFO, not LIFO order, simply by
+     * using poll rather than pop.  This can be useful in
+     * message-passing frameworks in which tasks are never joined,
+     * although with increased contention among task producers and
+     * consumers.
+     *
+     * WorkQueues are also used in a similar way for tasks submitted
+     * to the pool. We cannot mix these tasks in the same queues used
+     * by workers. Instead, we randomly associate submission queues
+     * with submitting threads, using a form of hashing.  The
+     * ThreadLocalRandom probe value serves as a hash code for
+     * choosing existing queues, and may be randomly repositioned upon
+     * contention with other submitters.  In essence, submitters act
+     * like workers except that they are restricted to executing local
+     * tasks that they submitted (or when known, subtasks thereof).
+     * Insertion of tasks in shared mode requires a lock. We use only
+     * a simple spinlock (using field "source"), because submitters
+     * encountering a busy queue move to a different position to use
+     * or create other queues. They block only when registering new
+     * queues.
+     *
+     * Management
+     * ==========
+     *
+     * The main throughput advantages of work-stealing stem from
+     * decentralized control -- workers mostly take tasks from
+     * themselves or each other, at rates that can exceed a billion
+     * per second.  Most non-atomic control is performed by some form
+     * of scanning across or within queues.  The pool itself creates,
+     * activates (enables scanning for and running tasks),
+     * deactivates, blocks, and terminates threads, all with minimal
+     * central information.  There are only a few properties that we
+     * can globally track or maintain, so we pack them into a small
+     * number of variables, often maintaining atomicity without
+     * blocking or locking.  Nearly all essentially atomic control
+     * state is held in a few volatile variables that are by far most
+     * often read (not written) as status and consistency checks. We
+     * pack as much information into them as we can.
+     *
+     * Field "ctl" contains 64 bits holding information needed to
+     * atomically decide to add, enqueue (on an event queue), and
+     * dequeue and release workers.  To enable this 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
+     * subfields.
+     *
+     * Field "mode" holds configuration parameters as well as lifetime
+     * status, atomically and monotonically setting SHUTDOWN, STOP,
+     * and finally TERMINATED bits. It is updated only via bitwise
+     * atomics (getAndBitwiseOr).
+     *
+     * Array "queues" holds references to WorkQueues.  It is updated
+     * (only during worker creation and termination) under the
+     * registrationLock, but is otherwise concurrently readable, and
+     * accessed directly (although always prefaced by acquireFences or
+     * other acquiring reads). To simplify index-based operations, the
+     * array size is always a power of two, and all readers must
+     * tolerate null slots.  Worker queues are at odd indices. Worker
+     * ids masked with SMASK match their index. Shared (submission)
+     * queues are at even indices. Grouping them together in this way
+     * simplifies and speeds up task scanning.
+     *
+     * 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 or task references that would prevent
+     * GC, all accesses to workQueues are via indices into the
+     * queues array (which is one source of some of the messy code
+     * constructions here). In essence, the queues array serves as
+     * a weak reference mechanism. Thus for example the stack top
+     * subfield of ctl stores indices, not references.
+     *
+     * Queuing Idle Workers. 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. These latencies are mainly a
+     * function of JVM park/unpark (and underlying OS) performance,
+     * which can be slow and variable.  In many usages, ramp-up time
+     * is the main limiting factor in overall performance, which is
+     * compounded at program start-up by JIT compilation and
+     * allocation. On the other hand, throughput degrades when too
+     * many threads poll for too few tasks.
+     *
+     * The "ctl" field atomically maintains total and "released"
+     * worker counts, plus the head of the available worker queue
+     * (actually stack, represented by the lower 32bit subfield of
+     * ctl).  Released workers are those known to be scanning for
+     * and/or running tasks. Unreleased ("available") workers are
+     * recorded in the ctl stack. These workers are made available for
+     * signalling by enqueuing in ctl (see method awaitWork).  The
+     * "queue" is a form of Treiber stack. This is ideal for
+     * activating threads in most-recently used order, and improves
+     * performance and locality, outweighing the disadvantages of
+     * being prone to contention and inability to release a worker
+     * unless it is topmost on stack. The top stack state holds the
+     * value of the "phase" field of the worker: its index and status,
+     * plus a version counter that, in addition to the count subfields
+     * (also serving as version stamps) provide protection against
+     * Treiber stack ABA effects.
+     *
+     * Creating workers. To create a worker, we pre-increment counts
+     * (serving as a reservation), and attempt to construct a
+     * ForkJoinWorkerThread via its factory. On starting, the new
+     * thread first invokes registerWorker, where it constructs a
+     * WorkQueue and is assigned an index in the queues array
+     * (expanding the array if necessary).  Upon any exception across
+     * these steps, or null return from factory, deregisterWorker
+     * adjusts counts and records accordingly.  If a null return, the
+     * pool continues running with fewer than the target number
+     * workers. If exceptional, the exception is propagated, generally
+     * to some external caller.
+     *
+     * WorkQueue field "phase" is used by both workers and the pool to
+     * manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is enqueued its
+     * phase field is set negative. Note that phase field updates lag
+     * queue CAS releases; seeing a negative phase does not guarantee
+     * that the worker is available. When queued, the lower 16 bits of
+     * its phase must hold its pool index. So we place the index there
+     * upon initialization and never modify these bits.
+     *
+     * The ctl field also serves as the basis for memory
+     * synchronization surrounding activation. This uses a more
+     * efficient version of a Dekker-like rule that task producers and
+     * consumers sync with each other by both writing/CASing ctl (even
+     * if to its current value).  However, rather than CASing ctl to
+     * its current value in the common case where no action is
+     * required, we reduce write contention by ensuring that
+     * signalWork invocations are prefaced with a full-volatile memory
+     * access (which is usually needed anyway).
+     *
+     * Signalling. Signals (in signalWork) cause new or reactivated
+     * workers to scan for tasks.  Method signalWork and its callers
+     * try to approximate the unattainable goal of having the right
+     * number of workers activated for the tasks at hand, but must err
+     * on the side of too many workers vs too few to avoid stalls.  If
+     * computations are purely tree structured, it suffices for every
+     * worker to activate another when it pushes a task into an empty
+     * queue, resulting in O(log(#threads)) steps to full activation.
+     * If instead, tasks come in serially from only a single producer,
+     * each worker taking its first (since the last quiescence) task
+     * from a queue should signal another if there are more tasks in
+     * that queue. This is equivalent to, but generally faster than,
+     * arranging the stealer take two tasks, re-pushing one on its own
+     * queue, and signalling (because its queue is empty), also
+     * resulting in logarithmic full activation time. Because we don't
+     * know about usage patterns (or most commonly, mixtures), we use
+     * both approaches.  We approximate the second rule by arranging
+     * that workers in scan() do not repeat signals when repeatedly
+     * taking tasks from any given queue, by remembering the previous
+     * one. There are narrow windows in which both rules may apply,
+     * leading to duplicate or unnecessary signals. Despite such
+     * limitations, these rules usually avoid slowdowns that otherwise
+     * occur when too many workers contend to take too few tasks, or
+     * when producers waste most of their time resignalling.  However,
+     * contention and overhead effects may still occur during ramp-up,
+     * ramp-down, and small computations involving only a few workers.
+     *
+     * Scanning. Method scan performs top-level scanning for (and
+     * execution of) tasks.  Scans by different workers and/or at
+     * different times are unlikely to poll queues in the same
+     * order. Each scan traverses and tries to poll from each queue in
+     * a pseudorandom permutation order by starting at a random index,
+     * and using a constant cyclically exhaustive stride; restarting
+     * upon contention.  (Non-top-level scans; for example in
+     * helpJoin, use simpler linear probes because they do not
+     * systematically contend with top-level scans.)  The pseudorandom
+     * generator need not have high-quality statistical properties in
+     * the long term. We use Marsaglia XorShifts, seeded with the Weyl
+     * sequence from ThreadLocalRandom probes, which are cheap and
+     * suffice. Scans do not otherwise explicitly take into account
+     * core affinities, loads, cache localities, etc, However, they do
+     * exploit temporal locality (which usually approximates these) by
+     * preferring to re-poll from the same queue after a successful
+     * poll before trying others (see method topLevelExec).  This
+     * reduces fairness, which is partially counteracted by using a
+     * one-shot form of poll (tryPoll) that may lose to other workers.
+     *
+     * Deactivation. Method scan returns a sentinel when no tasks are
+     * found, leading to deactivation (see awaitWork). The count
+     * fields in ctl allow accurate discovery of quiescent states
+     * (i.e., when all workers are idle) after deactivation. However,
+     * this may also race with new (external) submissions, so a
+     * recheck is also needed to determine quiescence. Upon apparently
+     * triggering quiescence, awaitWork re-scans and self-signals if
+     * it may have missed a signal. In other cases, a missed signal
+     * may transiently lower parallelism because deactivation does not
+     * necessarily mean that there is no more work, only that that
+     * there were no tasks not taken by other workers.  But more
+     * signals are generated (see above) to eventually reactivate if
+     * needed.
+     *
+     * 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
+     * period given by field keepAlive.
+     *
+     * Shutdown and Termination. A call to shutdownNow invokes
+     * tryTerminate to atomically set a mode bit. The calling thread,
+     * as well as every other worker thereafter terminating, helps
+     * terminate others by cancelling their unprocessed tasks, and
+     * waking them up. Calls to non-abrupt shutdown() preface this by
+     * checking isQuiescent before triggering the "STOP" phase of
+     * termination. To conform to ExecutorService invoke, invokeAll,
+     * and invokeAny specs, we must track pool status while waiting,
+     * and interrupt interruptible callers on termination (see
+     * ForkJoinTask.joinForPoolInvoke etc).
+     *
+     * Joining Tasks
+     * =============
+     *
+     * Normally, the first option when joining a task that is not done
+     * is to try to unfork it from local queue and run it.  Otherwise,
+     * any of several actions may be taken 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
+     * always 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 may
+     * 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
+     *      could be running if the steal had not occurred.
+     *
+     *   Compensating: Unless there are already enough live threads,
+     *      method tryCompensate() may create or re-activate a spare
+     *      thread to compensate for blocked joiners until they unblock.
+     *
+     * A third form (implemented via tryRemove) amounts to helping a
+     * hypothetical compensator: If we can readily tell that a
+     * possible action of a compensator is to steal and execute the
+     * task being joined, the joining thread can do so directly,
+     * without the need for a compensation thread; although with a
+     * (rare) possibility of reduced parallelism because of a
+     * transient gap in the queue array.
+     *
+     * Other intermediate forms available for specific task types (for
+     * example helpAsyncBlocker) often avoid or postpone the need for
+     * blocking or compensation.
+     *
+     * The ManagedBlocker extension API can't use helping so relies
+     * only on compensation in method awaitBlocker.
+     *
+     * The algorithm in helpJoin entails a form of "linear helping".
+     * Each worker records (in field "source") the id of the queue
+     * from which it last stole a task.  The scan in method helpJoin
+     * 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.  Thus, the joiner executes a task
+     * that would be on its own local deque if the to-be-joined task
+     * had not been stolen. This is a conservative variant of the
+     * approach described in Wagner & Calder "Leapfrogging: a portable
+     * technique for implementing efficient futures" SIGPLAN Notices,
+     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+     * mainly in that we only record queue ids, not full dependency
+     * links.  This requires a linear scan of the queues array to
+     * locate stealers, but isolates cost to when it is needed, rather
+     * than adding to per-task overhead. Also, searches are limited to
+     * direct and at most two levels of indirect stealers, after which
+     * there are rapidly diminishing returns on increased overhead.
+     * Searches can fail to locate stealers when stalls delay
+     * recording sources.  Further, even when accurately identified,
+     * stealers might not ever produce a task that the joiner can in
+     * turn help with. So, compensation is tried upon failure to find
+     * tasks to run.
+     *
+     * Joining CountedCompleters (see helpComplete) differs from (and
+     * is generally more efficient than) other cases because task
+     * eligibility is determined by checking completion chains rather
+     * than tracking stealers.
+     *
+     * Joining under timeouts (ForkJoinTask timed get) uses a
+     * constrained mixture of helping and compensating in part because
+     * pools (actually, only the common pool) may not have any
+     * available threads: If the pool is saturated (all available
+     * workers are busy), the caller tries to remove and otherwise
+     * help; else it blocks under compensation so that it may time out
+     * independently of any tasks.
+     *
+     * Compensation does not by default aim to keep exactly the target
+     * parallelism number of unblocked threads running at any given
+     * time. Some previous versions of this class employed immediate
+     * compensations for any blocked join. However, in practice, the
+     * vast majority of blockages are transient byproducts of GC and
+     * other JVM or OS activities that are made worse by replacement
+     * when they cause longer-term oversubscription.  Rather than
+     * impose arbitrary policies, we allow users to override the
+     * default of only adding threads upon apparent starvation.  The
+     * compensation mechanism may also be bounded.  Bounds for the
+     * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
+     * with programming errors and abuse before running out of
+     * resources to do so.
+     *
+     * Common Pool
+     * ===========
+     *
+     * The static common pool always exists after static
+     * initialization.  Since it (or any other created pool) need
+     * never be used, we minimize initial construction overhead and
+     * footprint to the setup of about a dozen fields.
+     *
+     * When external threads submit to the common pool, they can
+     * perform subtask processing (see helpComplete and related
+     * methods) upon joins.  This caller-helps policy makes it
+     * sensible to set common pool parallelism level to one (or more)
+     * less than the total number of available cores, or even zero for
+     * pure caller-runs.  We do not need to record whether external
+     * submissions are to the common pool -- if not, external help
+     * methods return quickly. These submitters would otherwise be
+     * blocked waiting for completion, so the extra effort (with
+     * liberally sprinkled task status checks) in inapplicable cases
+     * amounts to an odd form of limited spin-wait before blocking in
+     * ForkJoinTask.join.
+     *
+     * Guarantees for common pool parallelism zero are limited to
+     * tasks that are joined by their callers in a tree-structured
+     * fashion or use CountedCompleters (as is true for jdk
+     * parallelStreams). Support infiltrates several methods,
+     * including those that retry helping steps until we are sure that
+     * none apply if there are no workers.
+     *
+     * As a more appropriate default in managed environments, unless
+     * overridden by system properties, we use workers of subclass
+     * InnocuousForkJoinWorkerThread when there is a SecurityManager
+     * present. These workers have no permissions set, do not belong
+     * to any user-defined ThreadGroup, and erase all ThreadLocals
+     * after executing any top-level task.  The associated mechanics
+     * may be JVM-dependent and must access particular Thread class
+     * fields to achieve this effect.
+     *
+     * Interrupt handling
+     * ==================
+     *
+     * The framework is designed to manage task cancellation
+     * (ForkJoinTask.cancel) independently from the interrupt status
+     * of threads running tasks. (See the public ForkJoinTask
+     * documentation for rationale.)  Interrupts are issued only in
+     * tryTerminate, when workers should be terminating and tasks
+     * should be cancelled anyway. Interrupts are cleared only when
+     * necessary to ensure that calls to LockSupport.park do not loop
+     * indefinitely (park returns immediately if the current thread is
+     * interrupted). If so, interruption is reinstated after blocking
+     * if status could be visible during the scope of any task.  For
+     * cases in which task bodies are specified or desired to
+     * interrupt upon cancellation, ForkJoinTask.cancel can be
+     * overridden to do so (as is done for invoke{Any,All}).
+     *
+     * Memory placement
+     * ================
+     *
+     * Performance can be very sensitive to placement of instances of
+     * ForkJoinPool and WorkQueues and their queue arrays. To reduce
+     * false-sharing impact, the @Contended annotation isolates the
+     * ForkJoinPool.ctl field as well as the most heavily written
+     * WorkQueue fields. These mainly reduce cache traffic by scanners.
+     * WorkQueue arrays are presized large enough to avoid resizing
+     * (which transiently reduces throughput) in most tree-like
+     * computations, although not in some streaming usages. Initial
+     * sizes are not large enough to avoid secondary contention
+     * effects (especially for GC cardmarks) when queues are placed
+     * near each other in memory. This is common, but has different
+     * impact in different collectors and remains incompletely
+     * addressed.
+     *
+     * Style notes
+     * ===========
+     *
+     * Memory ordering relies mainly on atomic operations (CAS,
+     * getAndSet, getAndAdd) along with explicit fences.  This can be
+     * awkward and ugly, but also reflects the need to control
+     * outcomes across the unusual cases that arise in very racy code
+     * with very few invariants. All fields are read into locals
+     * before use, and null-checked if they are references, even if
+     * they can never be null under current usages.  Array accesses
+     * using masked indices include checks (that are always true) that
+     * the array length is non-zero to avoid compilers inserting more
+     * expensive traps.  This is usually done in a "C"-like style of
+     * listing declarations at the heads of methods or blocks, and
+     * using inline assignments on first encounter.  Nearly all
+     * explicit checks lead to bypass/return, not exception throws,
+     * because they may legitimately arise during shutdown.
+     *
+     * There is a lot of representation-level coupling among classes
+     * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
+     * fields of WorkQueue maintain data structures managed by
+     * ForkJoinPool, so are directly accessed.  There is little point
+     * trying to reduce this, since any associated future changes in
+     * representations will need to be accompanied by algorithmic
+     * changes anyway. Several methods intrinsically sprawl because
+     * they must accumulate sets of consistent reads of fields held in
+     * local variables. Some others are artificially broken up to
+     * reduce producer/consumer imbalances due to dynamic compilation.
+     * There are also other coding oddities (including several
+     * unnecessary-looking hoisted null checks) that help some methods
+     * perform reasonably even when interpreted (not compiled).
+     *
+     * The order of declarations in this file is (with a few exceptions):
+     * (1) Static utility functions
+     * (2) Nested (static) classes
+     * (3) Static fields
+     * (4) Fields, along with constants used when unpacking some of them
+     * (5) Internal control methods
+     * (6) Callbacks and other support for ForkJoinTask methods
+     * (7) Exported methods
+     * (8) Static block initializing statics in minimally dependent order
+     *
+     * Revision notes
+     * ==============
+     *
+     * The main sources of differences of ForkJoin classes from previous
+     * versions, up to Android API level 33, are:
+     *
+     * * ForkJoinTask now uses field "aux" to support blocking joins
+     *   and/or record exceptions, replacing reliance on builtin
+     *   monitors and side tables.
+     * * Scans probe slots (vs compare indices), along with related
+     *   changes that reduce performance differences across most
+     *   garbage collectors, and reduce contention.
+     * * Refactoring for better integration of special task types and
+     *   other capabilities that had been incrementally tacked on. Plus
+     *   many minor reworkings to improve consistency.
+     */
+
+    // Static utilities
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to modify threads.
+     */
+    private static void checkPermission() {
+        @SuppressWarnings("removal")
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(modifyThreadPermission);
+    }
+
+    @SuppressWarnings("removal")
+    static AccessControlContext contextWithPermissions(Permission ... perms) {
+        Permissions permissions = new Permissions();
+        for (Permission perm : perms)
+            permissions.add(perm);
+        return new AccessControlContext(
+            new ProtectionDomain[] { new ProtectionDomain(null, permissions) });
+    }
+
+    // Nested classes
+
+    /**
+     * 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.
+         * Returning null or throwing an exception may result in tasks
+         * never being executed.  If this method throws an exception,
+         * it is relayed to the caller of the method (for example
+         * {@code execute}) causing attempted thread creation. If this
+         * method returns null or throws an exception, it is not
+         * retried until the next attempted creation (for example
+         * another call to {@code execute}).
+         *
+         * @param pool the pool this thread works in
+         * @return the new worker thread, or {@code null} if the request
+         *         to create a thread is rejected
+         * @throws NullPointerException if the pool is null
+         */
+        public ForkJoinWorkerThread newThread(ForkJoinPool pool);
+    }
+
+    /**
+     * Default ForkJoinWorkerThreadFactory implementation; creates a
+     * new ForkJoinWorkerThread using the system class loader as the
+     * thread context class loader.
+     */
+    static final class DefaultForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+        // ACC for access to the factory
+        @SuppressWarnings("removal")
+        private static final AccessControlContext ACC = contextWithPermissions(
+            new RuntimePermission("getClassLoader"),
+            new RuntimePermission("setContextClassLoader"));
+        @SuppressWarnings("removal")
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    public ForkJoinWorkerThread run() {
+                        return new ForkJoinWorkerThread(null, pool, true, false);
+                    }},
+                ACC);
+        }
+    }
+
+    /**
+     * Factory for CommonPool unless overridden by System property.
+     * Creates InnocuousForkJoinWorkerThreads if a security manager is
+     * present at time of invocation.  Support requires that we break
+     * quite a lot of encapsulation (some via helper methods in
+     * ThreadLocalRandom) to access and set Thread fields.
+     */
+    static final class DefaultCommonPoolForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+        @SuppressWarnings("removal")
+        private static final AccessControlContext ACC = contextWithPermissions(
+            modifyThreadPermission,
+            new RuntimePermission("enableContextClassLoaderOverride"),
+            new RuntimePermission("modifyThreadGroup"),
+            new RuntimePermission("getClassLoader"),
+            new RuntimePermission("setContextClassLoader"));
+
+        @SuppressWarnings("removal")
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return AccessController.doPrivileged(
+                 new PrivilegedAction<>() {
+                     public ForkJoinWorkerThread run() {
+                         return System.getSecurityManager() == null ?
+                             new ForkJoinWorkerThread(null, pool, true, true):
+                             new ForkJoinWorkerThread.
+                             InnocuousForkJoinWorkerThread(pool); }},
+                 ACC);
+        }
+    }
+
+    // Constants shared across ForkJoinPool and WorkQueue
+
+    // Bounds
+    static final int SWIDTH       = 16;            // width of short
+    static final int SMASK        = 0xffff;        // short bits == max index
+    static final int MAX_CAP      = 0x7fff;        // max #workers - 1
+
+    // Masks and units for WorkQueue.phase and ctl sp subfield
+    static final int UNSIGNALLED  = 1 << 31;       // must be negative
+    static final int SS_SEQ       = 1 << 16;       // version count
+
+    // Mode bits and sentinels, some also used in WorkQueue fields
+    static final int FIFO         = 1 << 16;       // fifo queue or access mode
+    static final int SRC          = 1 << 17;       // set for valid queue ids
+    static final int INNOCUOUS    = 1 << 18;       // set for Innocuous workers
+    static final int QUIET        = 1 << 19;       // quiescing phase or source
+    static final int SHUTDOWN     = 1 << 24;
+    static final int TERMINATED   = 1 << 25;
+    static final int STOP         = 1 << 31;       // must be negative
+    static final int UNCOMPENSATE = 1 << 16;       // tryCompensate return
+
+    /**
+     * Initial capacity of work-stealing queue array.  Must be a power
+     * of two, at least 2. See above.
+     */
+    static final int INITIAL_QUEUE_CAPACITY = 1 << 8;
+
+    /**
+     * Queues supporting work-stealing as well as external task
+     * submission. See above for descriptions and algorithms.
+     */
+    static final class WorkQueue {
+        volatile int phase;        // versioned, negative if inactive
+        int stackPred;             // pool stack (ctl) predecessor link
+        int config;                // index, mode, ORed with SRC after init
+        int base;                  // index of next slot for poll
+        ForkJoinTask<?>[] array;   // the queued tasks; power of 2 size
+        final ForkJoinWorkerThread owner; // owning thread or null if shared
+
+        // segregate fields frequently updated but not read by scans or steals
+        @jdk.internal.vm.annotation.Contended("w")
+        int top;                   // index of next slot for push
+        @jdk.internal.vm.annotation.Contended("w")
+        volatile int source;       // source queue id, lock, or sentinel
+        @jdk.internal.vm.annotation.Contended("w")
+        int nsteals;               // number of steals from other queues
+
+        // Support for atomic operations
+        private static final VarHandle QA; // for array slots
+        private static final VarHandle SOURCE;
+        private static final VarHandle BASE;
+        static final ForkJoinTask<?> getSlot(ForkJoinTask<?>[] a, int i) {
+            return (ForkJoinTask<?>)QA.getAcquire(a, i);
+        }
+        static final ForkJoinTask<?> getAndClearSlot(ForkJoinTask<?>[] a,
+                                                     int i) {
+            return (ForkJoinTask<?>)QA.getAndSet(a, i, null);
+        }
+        static final void setSlotVolatile(ForkJoinTask<?>[] a, int i,
+                                          ForkJoinTask<?> v) {
+            QA.setVolatile(a, i, v);
+        }
+        static final boolean casSlotToNull(ForkJoinTask<?>[] a, int i,
+                                          ForkJoinTask<?> c) {
+            return QA.compareAndSet(a, i, c, null);
+        }
+        final boolean tryLock() {
+            return SOURCE.compareAndSet(this, 0, 1);
+        }
+        final void setBaseOpaque(int b) {
+            BASE.setOpaque(this, b);
+        }
+
+        /**
+         * Constructor used by ForkJoinWorkerThreads. Most fields
+         * are initialized upon thread start, in pool.registerWorker.
+         */
+        WorkQueue(ForkJoinWorkerThread owner, boolean isInnocuous) {
+            this.config = (isInnocuous) ? INNOCUOUS : 0;
+            this.owner = owner;
+        }
+
+        /**
+         * Constructor used for external queues.
+         */
+        WorkQueue(int config) {
+            array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+            this.config = config;
+            owner = null;
+            phase = -1;
+        }
+
+        /**
+         * Returns an exportable index (used by ForkJoinWorkerThread).
+         */
+        final int getPoolIndex() {
+            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+        }
+
+        /**
+         * Returns the approximate number of tasks in the queue.
+         */
+        final int queueSize() {
+            VarHandle.acquireFence(); // ensure fresh reads by external callers
+            int n = top - base;
+            return (n < 0) ? 0 : n;   // ignore transient negative
+        }
+
+        /**
+         * Provides a more conservative estimate of whether this queue
+         * has any tasks than does queueSize.
+         */
+        final boolean isEmpty() {
+            return !((source != 0 && owner == null) || top - base > 0);
+        }
+
+        /**
+         * Pushes a task. Call only by owner in unshared queues.
+         *
+         * @param task the task. Caller must ensure non-null.
+         * @param pool (no-op if null)
+         * @throws RejectedExecutionException if array cannot be resized
+         */
+        final void push(ForkJoinTask<?> task, ForkJoinPool pool) {
+            ForkJoinTask<?>[] a = array;
+            int s = top++, d = s - base, cap, m; // skip insert if disabled
+            if (a != null && pool != null && (cap = a.length) > 0) {
+                setSlotVolatile(a, (m = cap - 1) & s, task);
+                if (d == m)
+                    growArray();
+                if (d == m || a[m & (s - 1)] == null)
+                    pool.signalWork(); // signal if was empty or resized
+            }
+        }
+
+        /**
+         * Pushes task to a shared queue with lock already held, and unlocks.
+         *
+         * @return true if caller should signal work
+         */
+        final boolean lockedPush(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] a = array;
+            int s = top++, d = s - base, cap, m;
+            if (a != null && (cap = a.length) > 0) {
+                a[(m = cap - 1) & s] = task;
+                if (d == m)
+                    growArray();
+                source = 0; // unlock
+                if (d == m || a[m & (s - 1)] == null)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Doubles the capacity of array. Called by owner or with lock
+         * held after pre-incrementing top, which is reverted on
+         * allocation failure.
+         */
+        final void growArray() {
+            ForkJoinTask<?>[] oldArray = array, newArray;
+            int s = top - 1, oldCap, newCap;
+            if (oldArray != null && (oldCap = oldArray.length) > 0 &&
+                (newCap = oldCap << 1) > 0) { // skip if disabled
+                try {
+                    newArray = new ForkJoinTask<?>[newCap];
+                } catch (Throwable ex) {
+                    top = s;
+                    if (owner == null)
+                        source = 0; // unlock
+                    throw new RejectedExecutionException(
+                        "Queue capacity exceeded");
+                }
+                int newMask = newCap - 1, oldMask = oldCap - 1;
+                for (int k = oldCap; k > 0; --k, --s) {
+                    ForkJoinTask<?> x;        // poll old, push to new
+                    if ((x = getAndClearSlot(oldArray, s & oldMask)) == null)
+                        break;                // others already taken
+                    newArray[s & newMask] = x;
+                }
+                VarHandle.releaseFence();     // fill before publish
+                array = newArray;
+            }
+        }
+
+        // Variants of pop
+
+        /**
+         * Pops and returns task, or null if empty. Called only by owner.
+         */
+        private ForkJoinTask<?> pop() {
+            ForkJoinTask<?> t = null;
+            int s = top, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 && base != s-- &&
+                (t = getAndClearSlot(a, (cap - 1) & s)) != null)
+                top = s;
+            return t;
+        }
+
+        /**
+         * Pops the given task for owner only if it is at the current top.
+         */
+        final boolean tryUnpush(ForkJoinTask<?> task) {
+            int s = top, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 && base != s-- &&
+                casSlotToNull(a, (cap - 1) & s, task)) {
+                top = s;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Locking version of tryUnpush.
+         */
+        final boolean externalTryUnpush(ForkJoinTask<?> task) {
+            boolean taken = false;
+            for (;;) {
+                int s = top, cap, k; ForkJoinTask<?>[] a;
+                if ((a = array) == null || (cap = a.length) <= 0 ||
+                    a[k = (cap - 1) & (s - 1)] != task)
+                    break;
+                if (tryLock()) {
+                    if (top == s && array == a) {
+                        if (taken = casSlotToNull(a, k, task)) {
+                            top = s - 1;
+                            source = 0;
+                            break;
+                        }
+                    }
+                    source = 0; // release lock for retry
+                }
+                Thread.yield(); // trylock failure
+            }
+            return taken;
+        }
+
+        /**
+         * Deep form of tryUnpush: Traverses from top and removes task if
+         * present, shifting others to fill gap.
+         */
+        final boolean tryRemove(ForkJoinTask<?> task, boolean owned) {
+            boolean taken = false;
+            int p = top, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+            if ((a = array) != null && task != null && (cap = a.length) > 0) {
+                int m = cap - 1, s = p - 1, d = p - base;
+                for (int i = s, k; d > 0; --i, --d) {
+                    if ((t = a[k = i & m]) == task) {
+                        if (owned || tryLock()) {
+                            if ((owned || (array == a && top == p)) &&
+                                (taken = casSlotToNull(a, k, t))) {
+                                for (int j = i; j != s; ) // shift down
+                                    a[j & m] = getAndClearSlot(a, ++j & m);
+                                top = s;
+                            }
+                            if (!owned)
+                                source = 0;
+                        }
+                        break;
+                    }
+                }
+            }
+            return taken;
+        }
+
+        // variants of poll
+
+        /**
+         * Tries once to poll next task in FIFO order, failing on
+         * inconsistency or contention.
+         */
+        final ForkJoinTask<?> tryPoll() {
+            int cap, b, k; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                ForkJoinTask<?> t = getSlot(a, k = (cap - 1) & (b = base));
+                if (base == b++ && t != null && casSlotToNull(a, k, t)) {
+                    setBaseOpaque(b);
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> nextLocalTask(int cfg) {
+            ForkJoinTask<?> t = null;
+            int s = top, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                for (int b, d;;) {
+                    if ((d = s - (b = base)) <= 0)
+                        break;
+                    if (d == 1 || (cfg & FIFO) == 0) {
+                        if ((t = getAndClearSlot(a, --s & (cap - 1))) != null)
+                            top = s;
+                        break;
+                    }
+                    if ((t = getAndClearSlot(a, b++ & (cap - 1))) != null) {
+                        setBaseOpaque(b);
+                        break;
+                    }
+                }
+            }
+            return t;
+        }
+
+        /**
+         * Takes next task, if one exists, using configured mode.
+         */
+        final ForkJoinTask<?> nextLocalTask() {
+            return nextLocalTask(config);
+        }
+
+        /**
+         * Returns next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> peek() {
+            VarHandle.acquireFence();
+            int cap; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (cap = a.length) > 0) ?
+                a[(cap - 1) & ((config & FIFO) != 0 ? base : top - 1)] : null;
+        }
+
+        // specialized execution methods
+
+        /**
+         * Runs the given (stolen) task if nonnull, as well as
+         * remaining local tasks and/or others available from the
+         * given queue.
+         */
+        final void topLevelExec(ForkJoinTask<?> task, WorkQueue q) {
+            int cfg = config, nstolen = 1;
+            while (task != null) {
+                task.doExec();
+                if ((task = nextLocalTask(cfg)) == null &&
+                    q != null && (task = q.tryPoll()) != null)
+                    ++nstolen;
+            }
+            nsteals += nstolen;
+            source = 0;
+            if ((cfg & INNOCUOUS) != 0)
+                ThreadLocalRandom.eraseThreadLocals(Thread.currentThread());
+        }
+
+        /**
+         * Tries to pop and run tasks within the target's computation
+         * until done, not found, or limit exceeded.
+         *
+         * @param task root of CountedCompleter computation
+         * @param owned true if owned by a ForkJoinWorkerThread
+         * @param limit max runs, or zero for no limit
+         * @return task status on exit
+         */
+        final int helpComplete(ForkJoinTask<?> task, boolean owned, int limit) {
+            int status = 0, cap, k, p, s; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+            while (task != null && (status = task.status) >= 0 &&
+                   (a = array) != null && (cap = a.length) > 0 &&
+                   (t = a[k = (cap - 1) & (s = (p = top) - 1)])
+                   instanceof CountedCompleter) {
+                CountedCompleter<?> f = (CountedCompleter<?>)t;
+                boolean taken = false;
+                for (;;) {     // exec if root task is a completer of t
+                    if (f == task) {
+                        if (owned) {
+                            if ((taken = casSlotToNull(a, k, t)))
+                                top = s;
+                        }
+                        else if (tryLock()) {
+                            if (top == p && array == a &&
+                                (taken = casSlotToNull(a, k, t)))
+                                top = s;
+                            source = 0;
+                        }
+                        if (taken)
+                            t.doExec();
+                        else if (!owned)
+                            Thread.yield(); // tryLock failure
+                        break;
+                    }
+                    else if ((f = f.completer) == null)
+                        break;
+                }
+                if (taken && limit != 0 && --limit == 0)
+                    break;
+            }
+            return status;
+        }
+
+        /**
+         * Tries to poll and run AsynchronousCompletionTasks until
+         * none found or blocker is released.
+         *
+         * @param blocker the blocker
+         */
+        final void helpAsyncBlocker(ManagedBlocker blocker) {
+            int cap, b, d, k; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+            while (blocker != null && (d = top - (b = base)) > 0 &&
+                   (a = array) != null && (cap = a.length) > 0 &&
+                   (((t = getSlot(a, k = (cap - 1) & b)) == null && d > 1) ||
+                    t instanceof
+                    CompletableFuture.AsynchronousCompletionTask) &&
+                   !blocker.isReleasable()) {
+                if (t != null && base == b++ && casSlotToNull(a, k, t)) {
+                    setBaseOpaque(b);
+                    t.doExec();
+                }
+            }
+        }
+
+        // misc
+
+        /** AccessControlContext for innocuous workers, created on 1st use. */
+        @SuppressWarnings("removal")
+        private static AccessControlContext INNOCUOUS_ACC;
+
+        /**
+         * Initializes (upon registration) InnocuousForkJoinWorkerThreads.
+         */
+        @SuppressWarnings("removal")
+        final void initializeInnocuousWorker() {
+            AccessControlContext acc; // racy construction OK
+            if ((acc = INNOCUOUS_ACC) == null)
+                INNOCUOUS_ACC = acc = new AccessControlContext(
+                    new ProtectionDomain[] { new ProtectionDomain(null, null) });
+            Thread t = Thread.currentThread();
+            ThreadLocalRandom.setInheritedAccessControlContext(t, acc);
+            ThreadLocalRandom.eraseThreadLocals(t);
+        }
+
+        /**
+         * Returns true if owned by a worker thread and not known to be blocked.
+         */
+        final boolean isApparentlyUnblocked() {
+            Thread wt; Thread.State s;
+            return ((wt = owner) != null &&
+                    (s = wt.getState()) != Thread.State.BLOCKED &&
+                    s != Thread.State.WAITING &&
+                    s != Thread.State.TIMED_WAITING);
+        }
+
+        static {
+            try {
+                QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                SOURCE = l.findVarHandle(WorkQueue.class, "source", int.class);
+                BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+    }
+
+    // static fields (initialized in static initializer below)
+
+    /**
+     * 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.
+     */
+    static final RuntimePermission modifyThreadPermission;
+
+    /**
+     * Common (static) pool. Non-null for public use unless a static
+     * construction exception, but internal usages null-check on use
+     * to paranoically avoid potential initialization circularities
+     * as well as to simplify generated code.
+     */
+    static final ForkJoinPool common;
+
+    /**
+     * Common pool parallelism. To allow simpler use and management
+     * when common pool threads are disabled, we allow the underlying
+     * common.parallelism field to be zero, but in that case still report
+     * parallelism as 1 to reflect resulting caller-runs mechanics.
+     */
+    static final int COMMON_PARALLELISM;
+
+    /**
+     * Limit on spare thread construction in tryCompensate.
+     */
+    private static final int COMMON_MAX_SPARES;
+
+    /**
+     * Sequence number for creating worker names
+     */
+    private static volatile int poolIds;
+
+    // static configuration constants
+
+    /**
+     * Default idle timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work
+     */
+    private static final long DEFAULT_KEEPALIVE = 60_000L;
+
+    /**
+     * Undershoot tolerance for idle timeouts
+     */
+    private static final long TIMEOUT_SLOP = 20L;
+
+    /**
+     * The default value for COMMON_MAX_SPARES.  Overridable using the
+     * "java.util.concurrent.ForkJoinPool.common.maximumSpares" system
+     * property.  The default value is far in excess of normal
+     * requirements, but also far short of MAX_CAP and typical OS
+     * thread limits, so allows JVMs to catch misuse/abuse before
+     * running out of resources needed to do so.
+     */
+    private static final int DEFAULT_COMMON_MAX_SPARES = 256;
+
+    /*
+     * Bits and masks for field ctl, packed with 4 16 bit subfields:
+     * RC: Number of released (unqueued) workers minus target parallelism
+     * TC: Number of total workers minus target parallelism
+     * SS: version count and status of top waiting thread
+     * ID: poolIndex of top of Treiber stack of waiters
+     *
+     * When convenient, we can extract the lower 32 stack top bits
+     * (including version bits) as sp=(int)ctl.  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 unqueued
+     * workers, when tc is negative, there are not enough total
+     * workers.  When sp is non-zero, there are waiting workers.  To
+     * deal with possibly negative fields, we use casts in and out of
+     * "short" and/or signed shifts to maintain signedness.
+     *
+     * Because it occupies uppermost bits, we can add one release
+     * count using getAndAdd of RC_UNIT, rather than CAS, when
+     * returning from a blocked join.  Other updates entail multiple
+     * subfields and masking, requiring CAS.
+     *
+     * The limits packed in field "bounds" are also offset by the
+     * parallelism level to make them comparable to the ctl rc and tc
+     * fields.
+     */
+
+    // Lower and upper word masks
+    private static final long SP_MASK    = 0xffffffffL;
+    private static final long UC_MASK    = ~SP_MASK;
+
+    // Release counts
+    private static final int  RC_SHIFT   = 48;
+    private static final long RC_UNIT    = 0x0001L << RC_SHIFT;
+    private static final long RC_MASK    = 0xffffL << RC_SHIFT;
+
+    // Total counts
+    private static final int  TC_SHIFT   = 32;
+    private static final long TC_UNIT    = 0x0001L << TC_SHIFT;
+    private static final long TC_MASK    = 0xffffL << TC_SHIFT;
+    private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
+
+    // Instance fields
+
+    final long keepAlive;                // milliseconds before dropping if idle
+    volatile long stealCount;            // collects worker nsteals
+    int scanRover;                       // advances across pollScan calls
+    volatile int threadIds;              // for worker thread names
+    final int bounds;                    // min, max threads packed as shorts
+    volatile int mode;                   // parallelism, runstate, queue mode
+    WorkQueue[] queues;                  // main registry
+    final ReentrantLock registrationLock;
+    Condition termination;               // lazily constructed
+    final String workerNamePrefix;       // null for common pool
+    final ForkJoinWorkerThreadFactory factory;
+    final UncaughtExceptionHandler ueh;  // per-worker UEH
+    final Predicate<? super ForkJoinPool> saturate;
+
+    @jdk.internal.vm.annotation.Contended("fjpctl") // segregate
+    volatile long ctl;                   // main pool control
+
+    // Support for atomic operations
+    private static final VarHandle CTL;
+    private static final VarHandle MODE;
+    private static final VarHandle THREADIDS;
+    private static final VarHandle POOLIDS;
+    private boolean compareAndSetCtl(long c, long v) {
+        return CTL.compareAndSet(this, c, v);
+    }
+    private long compareAndExchangeCtl(long c, long v) {
+        return (long)CTL.compareAndExchange(this, c, v);
+    }
+    private long getAndAddCtl(long v) {
+        return (long)CTL.getAndAdd(this, v);
+    }
+    private int getAndBitwiseOrMode(int v) {
+        return (int)MODE.getAndBitwiseOr(this, v);
+    }
+    private int getAndAddThreadIds(int x) {
+        return (int)THREADIDS.getAndAdd(this, x);
+    }
+    private static int getAndAddPoolIds(int x) {
+        return (int)POOLIDS.getAndAdd(x);
+    }
+
+    // Creating, registering and deregistering workers
+
+    /**
+     * Tries to construct and start one worker. Assumes that total
+     * count has already been incremented as a reservation.  Invokes
+     * deregisterWorker on any failure.
+     *
+     * @return true if successful
+     */
+    private boolean createWorker() {
+        ForkJoinWorkerThreadFactory fac = factory;
+        Throwable ex = null;
+        ForkJoinWorkerThread wt = null;
+        try {
+            if (fac != null && (wt = fac.newThread(this)) != null) {
+                wt.start();
+                return true;
+            }
+        } catch (Throwable rex) {
+            ex = rex;
+        }
+        deregisterWorker(wt, ex);
+        return false;
+    }
+
+    /**
+     * Provides a name for ForkJoinWorkerThread constructor.
+     */
+    final String nextWorkerThreadName() {
+        String prefix = workerNamePrefix;
+        int tid = getAndAddThreadIds(1) + 1;
+        if (prefix == null) // commonPool has no prefix
+            prefix = "ForkJoinPool.commonPool-worker-";
+        return prefix.concat(Integer.toString(tid));
+    }
+
+    /**
+     * Finishes initializing and records owned queue.
+     *
+     * @param w caller's WorkQueue
+     */
+    final void registerWorker(WorkQueue w) {
+        ReentrantLock lock = registrationLock;
+        ThreadLocalRandom.localInit();
+        int seed = ThreadLocalRandom.getProbe();
+        if (w != null && lock != null) {
+            int modebits = (mode & FIFO) | w.config;
+            w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+            w.stackPred = seed;                         // stash for runWorker
+            if ((modebits & INNOCUOUS) != 0)
+                w.initializeInnocuousWorker();
+            int id = (seed << 1) | 1;                   // initial index guess
+            lock.lock();
+            try {
+                WorkQueue[] qs; int n;                  // find queue index
+                if ((qs = queues) != null && (n = qs.length) > 0) {
+                    int k = n, m = n - 1;
+                    for (; qs[id &= m] != null && k > 0; id -= 2, k -= 2);
+                    if (k == 0)
+                        id = n | 1;                     // resize below
+                    w.phase = w.config = id | modebits; // now publishable
+
+                    if (id < n)
+                        qs[id] = w;
+                    else {                              // expand array
+                        int an = n << 1, am = an - 1;
+                        WorkQueue[] as = new WorkQueue[an];
+                        as[id & am] = w;
+                        for (int j = 1; j < n; j += 2)
+                            as[j] = qs[j];
+                        for (int j = 0; j < n; j += 2) {
+                            WorkQueue q;
+                            if ((q = qs[j]) != null)    // shared queues may move
+                                as[q.config & am] = q;
+                        }
+                        VarHandle.releaseFence();       // fill before publish
+                        queues = as;
+                    }
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Final callback from terminating worker, as well as upon failure
+     * to construct or start a worker.  Removes record of worker from
+     * array, and adjusts counts. If pool is shutting down, tries to
+     * complete termination.
+     *
+     * @param wt the worker thread, or null if construction failed
+     * @param ex the exception causing failure, or null if none
+     */
+    final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
+        ReentrantLock lock = registrationLock;
+        WorkQueue w = null;
+        int cfg = 0;
+        if (wt != null && (w = wt.workQueue) != null && lock != null) {
+            WorkQueue[] qs; int n, i;
+            cfg = w.config;
+            long ns = w.nsteals & 0xffffffffL;
+            lock.lock();                             // remove index from array
+            if ((qs = queues) != null && (n = qs.length) > 0 &&
+                qs[i = cfg & (n - 1)] == w)
+                qs[i] = null;
+            stealCount += ns;                        // accumulate steals
+            lock.unlock();
+            long c = ctl;
+            if ((cfg & QUIET) == 0) // unless self-signalled, decrement counts
+                do {} while (c != (c = compareAndExchangeCtl(
+                                       c, ((RC_MASK & (c - RC_UNIT)) |
+                                           (TC_MASK & (c - TC_UNIT)) |
+                                           (SP_MASK & c)))));
+            else if ((int)c == 0)                    // was dropped on timeout
+                cfg = 0;                             // suppress signal if last
+            for (ForkJoinTask<?> t; (t = w.pop()) != null; )
+                ForkJoinTask.cancelIgnoringExceptions(t); // cancel tasks
+        }
+
+        if (!tryTerminate(false, false) && w != null && (cfg & SRC) != 0)
+            signalWork();                            // possibly replace worker
+        if (ex != null)
+            ForkJoinTask.rethrow(ex);
+    }
+
+    /*
+     * Tries to create or release a worker if too few are running.
+     */
+    final void signalWork() {
+        for (long c = ctl; c < 0L;) {
+            int sp, i; WorkQueue[] qs; WorkQueue v;
+            if ((sp = (int)c & ~UNSIGNALLED) == 0) {  // no idle workers
+                if ((c & ADD_WORKER) == 0L)           // enough total workers
+                    break;
+                if (c == (c = compareAndExchangeCtl(
+                              c, ((RC_MASK & (c + RC_UNIT)) |
+                                  (TC_MASK & (c + TC_UNIT)))))) {
+                    createWorker();
+                    break;
+                }
+            }
+            else if ((qs = queues) == null)
+                break;                                // unstarted/terminated
+            else if (qs.length <= (i = sp & SMASK))
+                break;                                // terminated
+            else if ((v = qs[i]) == null)
+                break;                                // terminating
+            else {
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + RC_UNIT));
+                Thread vt = v.owner;
+                if (c == (c = compareAndExchangeCtl(c, nc))) {
+                    v.phase = sp;
+                    LockSupport.unpark(vt);           // release idle worker
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     * See above for explanation.
+     *
+     * @param w caller's WorkQueue (may be null on failed initialization)
+     */
+    final void runWorker(WorkQueue w) {
+        if (mode >= 0 && w != null) {           // skip on failed init
+            w.config |= SRC;                    // mark as valid source
+            int r = w.stackPred, src = 0;       // use seed from registerWorker
+            do {
+                r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+            } while ((src = scan(w, src, r)) >= 0 ||
+                     (src = awaitWork(w)) == 0);
+        }
+    }
+
+    /**
+     * Scans for and if found executes top-level tasks: Tries to poll
+     * each queue starting at a random index with random stride,
+     * returning source id or retry indicator if contended or
+     * inconsistent.
+     *
+     * @param w caller's WorkQueue
+     * @param prevSrc the previous queue stolen from in current phase, or 0
+     * @param r random seed
+     * @return id of queue if taken, negative if none found, prevSrc for retry
+     */
+    private int scan(WorkQueue w, int prevSrc, int r) {
+        WorkQueue[] qs = queues;
+        int n = (w == null || qs == null) ? 0 : qs.length;
+        for (int step = (r >>> 16) | 1, i = n; i > 0; --i, r += step) {
+            int j, cap, b; WorkQueue q; ForkJoinTask<?>[] a;
+            if ((q = qs[j = r & (n - 1)]) != null && // poll at qs[j].array[k]
+                (a = q.array) != null && (cap = a.length) > 0) {
+                int k = (cap - 1) & (b = q.base), nextBase = b + 1;
+                int nextIndex = (cap - 1) & nextBase, src = j | SRC;
+                ForkJoinTask<?> t = WorkQueue.getSlot(a, k);
+                if (q.base != b)                // inconsistent
+                    return prevSrc;
+                else if (t != null && WorkQueue.casSlotToNull(a, k, t)) {
+                    q.base = nextBase;
+                    ForkJoinTask<?> next = a[nextIndex];
+                    if ((w.source = src) != prevSrc && next != null)
+                        signalWork();           // propagate
+                    w.topLevelExec(t, q);
+                    return src;
+                }
+                else if (a[nextIndex] != null)  // revisit
+                    return prevSrc;
+            }
+        }
+        return (queues != qs) ? prevSrc: -1;    // possibly resized
+    }
+
+    /**
+     * Advances worker phase, pushes onto ctl stack, and awaits signal
+     * or reports termination.
+     *
+     * @return negative if terminated, else 0
+     */
+    private int awaitWork(WorkQueue w) {
+        if (w == null)
+            return -1;                       // already terminated
+        int phase = (w.phase + SS_SEQ) & ~UNSIGNALLED;
+        w.phase = phase | UNSIGNALLED;       // advance phase
+        long prevCtl = ctl, c;               // enqueue
+        do {
+            w.stackPred = (int)prevCtl;
+            c = ((prevCtl - RC_UNIT) & UC_MASK) | (phase & SP_MASK);
+        } while (prevCtl != (prevCtl = compareAndExchangeCtl(prevCtl, c)));
+
+        Thread.interrupted();                // clear status
+        LockSupport.setCurrentBlocker(this); // prepare to block (exit also OK)
+        long deadline = 0L;                  // nonzero if possibly quiescent
+        int ac = (int)(c >> RC_SHIFT), md;
+        if ((md = mode) < 0)                 // pool is terminating
+            return -1;
+        else if ((md & SMASK) + ac <= 0) {
+            boolean checkTermination = (md & SHUTDOWN) != 0;
+            if ((deadline = System.currentTimeMillis() + keepAlive) == 0L)
+                deadline = 1L;               // avoid zero
+            WorkQueue[] qs = queues;         // check for racing submission
+            int n = (qs == null) ? 0 : qs.length;
+            for (int i = 0; i < n; i += 2) {
+                WorkQueue q; ForkJoinTask<?>[] a; int cap, b;
+                if (ctl != c) {              // already signalled
+                    checkTermination = false;
+                    break;
+                }
+                else if ((q = qs[i]) != null &&
+                         (a = q.array) != null && (cap = a.length) > 0 &&
+                         ((b = q.base) != q.top || a[(cap - 1) & b] != null ||
+                          q.source != 0)) {
+                    if (compareAndSetCtl(c, prevCtl))
+                        w.phase = phase;     // self-signal
+                    checkTermination = false;
+                    break;
+                }
+            }
+            if (checkTermination && tryTerminate(false, false))
+                return -1;                   // trigger quiescent termination
+        }
+
+        for (boolean alt = false;;) {        // await activation or termination
+            if (w.phase >= 0)
+                break;
+            else if (mode < 0)
+                return -1;
+            else if ((c = ctl) == prevCtl)
+                Thread.onSpinWait();         // signal in progress
+            else if (!(alt = !alt))          // check between park calls
+                Thread.interrupted();
+            else if (deadline == 0L)
+                LockSupport.park();
+            else if (deadline - System.currentTimeMillis() > TIMEOUT_SLOP)
+                LockSupport.parkUntil(deadline);
+            else if (((int)c & SMASK) == (w.config & SMASK) &&
+                     compareAndSetCtl(c, ((UC_MASK & (c - TC_UNIT)) |
+                                          (prevCtl & SP_MASK)))) {
+                w.config |= QUIET;           // sentinel for deregisterWorker
+                return -1;                   // drop on timeout
+            }
+            else if ((deadline += keepAlive) == 0L)
+                deadline = 1L;               // not at head; restart timer
+        }
+        return 0;
+    }
+
+    // Utilities used by ForkJoinTask
+
+    /**
+     * Returns true if can start terminating if enabled, or already terminated
+     */
+    final boolean canStop() {
+        outer: for (long oldSum = 0L;;) { // repeat until stable
+            int md; WorkQueue[] qs;  long c;
+            if ((qs = queues) == null || ((md = mode) & STOP) != 0)
+                return true;
+            if ((md & SMASK) + (int)((c = ctl) >> RC_SHIFT) > 0)
+                break;
+            long checkSum = c;
+            for (int i = 1; i < qs.length; i += 2) { // scan submitters
+                WorkQueue q; ForkJoinTask<?>[] a; int s = 0, cap;
+                if ((q = qs[i]) != null && (a = q.array) != null &&
+                    (cap = a.length) > 0 &&
+                    ((s = q.top) != q.base || a[(cap - 1) & s] != null ||
+                     q.source != 0))
+                    break outer;
+                checkSum += (((long)i) << 32) ^ s;
+            }
+            if (oldSum == (oldSum = checkSum) && queues == qs)
+                return true;
+        }
+        return (mode & STOP) != 0; // recheck mode on false return
+    }
+
+    /**
+     * Tries to decrement counts (sometimes implicitly) and possibly
+     * arrange for a compensating worker in preparation for
+     * blocking. May fail due to interference, in which case -1 is
+     * returned so caller may retry. A zero return value indicates
+     * that the caller doesn't need to re-adjust counts when later
+     * unblocked.
+     *
+     * @param c incoming ctl value
+     * @return UNCOMPENSATE: block then adjust, 0: block, -1 : retry
+     */
+    private int tryCompensate(long c) {
+        Predicate<? super ForkJoinPool> sat;
+        int md = mode, b = bounds;
+        // counts are signed; centered at parallelism level == 0
+        int minActive = (short)(b & SMASK),
+            maxTotal  = b >>> SWIDTH,
+            active    = (int)(c >> RC_SHIFT),
+            total     = (short)(c >>> TC_SHIFT),
+            sp        = (int)c & ~UNSIGNALLED;
+        if ((md & SMASK) == 0)
+            return 0;                  // cannot compensate if parallelism zero
+        else if (total >= 0) {
+            if (sp != 0) {                        // activate idle worker
+                WorkQueue[] qs; int n; WorkQueue v;
+                if ((qs = queues) != null && (n = qs.length) > 0 &&
+                    (v = qs[sp & (n - 1)]) != null) {
+                    Thread vt = v.owner;
+                    long nc = ((long)v.stackPred & SP_MASK) | (UC_MASK & c);
+                    if (compareAndSetCtl(c, nc)) {
+                        v.phase = sp;
+                        LockSupport.unpark(vt);
+                        return UNCOMPENSATE;
+                    }
+                }
+                return -1;                        // retry
+            }
+            else if (active > minActive) {        // reduce parallelism
+                long nc = ((RC_MASK & (c - RC_UNIT)) | (~RC_MASK & c));
+                return compareAndSetCtl(c, nc) ? UNCOMPENSATE : -1;
+            }
+        }
+        if (total < maxTotal) {                   // expand pool
+            long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
+            return (!compareAndSetCtl(c, nc) ? -1 :
+                    !createWorker() ? 0 : UNCOMPENSATE);
+        }
+        else if (!compareAndSetCtl(c, c))         // validate
+            return -1;
+        else if ((sat = saturate) != null && sat.test(this))
+            return 0;
+        else
+            throw new RejectedExecutionException(
+                "Thread limit exceeded replacing blocked worker");
+    }
+
+    /**
+     * Readjusts RC count; called from ForkJoinTask after blocking.
+     */
+    final void uncompensate() {
+        getAndAddCtl(RC_UNIT);
+    }
+
+    /**
+     * Helps if possible until the given task is done.  Scans other
+     * queues for a task produced by one of w's stealers; returning
+     * compensated blocking sentinel if none are found.
+     *
+     * @param task the task
+     * @param w caller's WorkQueue
+     * @param canHelp if false, compensate only
+     * @return task status on exit, or UNCOMPENSATE for compensated blocking
+     */
+    final int helpJoin(ForkJoinTask<?> task, WorkQueue w, boolean canHelp) {
+        int s = 0;
+        if (task != null && w != null) {
+            int wsrc = w.source, wid = w.config & SMASK, r = wid + 2;
+            boolean scan = true;
+            long c = 0L;                          // track ctl stability
+            outer: for (;;) {
+                if ((s = task.status) < 0)
+                    break;
+                else if (scan = !scan) {          // previous scan was empty
+                    if (mode < 0)
+                        ForkJoinTask.cancelIgnoringExceptions(task);
+                    else if (c == (c = ctl) && (s = tryCompensate(c)) >= 0)
+                        break;                    // block
+                }
+                else if (canHelp) {               // scan for subtasks
+                    WorkQueue[] qs = queues;
+                    int n = (qs == null) ? 0 : qs.length, m = n - 1;
+                    for (int i = n; i > 0; i -= 2, r += 2) {
+                        int j; WorkQueue q, x, y; ForkJoinTask<?>[] a;
+                        if ((q = qs[j = r & m]) != null) {
+                            int sq = q.source & SMASK, cap, b;
+                            if ((a = q.array) != null && (cap = a.length) > 0) {
+                                int k = (cap - 1) & (b = q.base);
+                                int nextBase = b + 1, src = j | SRC, sx;
+                                ForkJoinTask<?> t = WorkQueue.getSlot(a, k);
+                                boolean eligible = sq == wid ||
+                                    ((x = qs[sq & m]) != null &&   // indirect
+                                     ((sx = (x.source & SMASK)) == wid ||
+                                      ((y = qs[sx & m]) != null && // 2-indirect
+                                       (y.source & SMASK) == wid)));
+                                if ((s = task.status) < 0)
+                                    break outer;
+                                else if ((q.source & SMASK) != sq ||
+                                         q.base != b)
+                                    scan = true;          // inconsistent
+                                else if (t == null)
+                                    scan |= (a[nextBase & (cap - 1)] != null ||
+                                             q.top != b); // lagging
+                                else if (eligible) {
+                                    if (WorkQueue.casSlotToNull(a, k, t)) {
+                                        q.base = nextBase;
+                                        w.source = src;
+                                        t.doExec();
+                                        w.source = wsrc;
+                                    }
+                                    scan = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Extra helpJoin steps for CountedCompleters.  Scans for and runs
+     * subtasks of the given root task, returning if none are found.
+     *
+     * @param task root of CountedCompleter computation
+     * @param w caller's WorkQueue
+     * @param owned true if owned by a ForkJoinWorkerThread
+     * @return task status on exit
+     */
+    final int helpComplete(ForkJoinTask<?> task, WorkQueue w, boolean owned) {
+        int s = 0;
+        if (task != null && w != null) {
+            int r = w.config;
+            boolean scan = true, locals = true;
+            long c = 0L;
+            outer: for (;;) {
+                if (locals) {                     // try locals before scanning
+                    if ((s = w.helpComplete(task, owned, 0)) < 0)
+                        break;
+                    locals = false;
+                }
+                else if ((s = task.status) < 0)
+                    break;
+                else if (scan = !scan) {
+                    if (c == (c = ctl))
+                        break;
+                }
+                else {                            // scan for subtasks
+                    WorkQueue[] qs = queues;
+                    int n = (qs == null) ? 0 : qs.length;
+                    for (int i = n; i > 0; --i, ++r) {
+                        int j, cap, b; WorkQueue q; ForkJoinTask<?>[] a;
+                        boolean eligible = false;
+                        if ((q = qs[j = r & (n - 1)]) != null &&
+                            (a = q.array) != null && (cap = a.length) > 0) {
+                            int k = (cap - 1) & (b = q.base), nextBase = b + 1;
+                            ForkJoinTask<?> t = WorkQueue.getSlot(a, k);
+                            if (t instanceof CountedCompleter) {
+                                CountedCompleter<?> f = (CountedCompleter<?>)t;
+                                do {} while (!(eligible = (f == task)) &&
+                                             (f = f.completer) != null);
+                            }
+                            if ((s = task.status) < 0)
+                                break outer;
+                            else if (q.base != b)
+                                scan = true;       // inconsistent
+                            else if (t == null)
+                                scan |= (a[nextBase & (cap - 1)] != null ||
+                                         q.top != b);
+                            else if (eligible) {
+                                if (WorkQueue.casSlotToNull(a, k, t)) {
+                                    q.setBaseOpaque(nextBase);
+                                    t.doExec();
+                                    locals = true;
+                                }
+                                scan = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Scans for and returns a polled task, if available.  Used only
+     * for untracked polls. Begins scan at an index (scanRover)
+     * advanced on each call, to avoid systematic unfairness.
+     *
+     * @param submissionsOnly if true, only scan submission queues
+     */
+    private ForkJoinTask<?> pollScan(boolean submissionsOnly) {
+        VarHandle.acquireFence();
+        int r = scanRover += 0x61c88647; // Weyl increment; raciness OK
+        if (submissionsOnly)             // even indices only
+            r &= ~1;
+        int step = (submissionsOnly) ? 2 : 1;
+        WorkQueue[] qs; int n;
+        while ((qs = queues) != null && (n = qs.length) > 0) {
+            boolean scan = false;
+            for (int i = 0; i < n; i += step) {
+                int j, cap, b; WorkQueue q; ForkJoinTask<?>[] a;
+                if ((q = qs[j = (n - 1) & (r + i)]) != null &&
+                    (a = q.array) != null && (cap = a.length) > 0) {
+                    int k = (cap - 1) & (b = q.base), nextBase = b + 1;
+                    ForkJoinTask<?> t = WorkQueue.getSlot(a, k);
+                    if (q.base != b)
+                        scan = true;
+                    else if (t == null)
+                        scan |= (q.top != b || a[nextBase & (cap - 1)] != null);
+                    else if (!WorkQueue.casSlotToNull(a, k, t))
+                        scan = true;
+                    else {
+                        q.setBaseOpaque(nextBase);
+                        return t;
+                    }
+                }
+            }
+            if (!scan && queues == qs)
+                break;
+        }
+        return null;
+    }
+
+    /**
+     * Runs tasks until {@code isQuiescent()}. Rather than blocking
+     * when tasks cannot be found, rescans until all others cannot
+     * find tasks either.
+     *
+     * @param nanos max wait time (Long.MAX_VALUE if effectively untimed)
+     * @param interruptible true if return on interrupt
+     * @return positive if quiescent, negative if interrupted, else 0
+     */
+    final int helpQuiescePool(WorkQueue w, long nanos, boolean interruptible) {
+        if (w == null)
+            return 0;
+        long startTime = System.nanoTime(), parkTime = 0L;
+        int prevSrc = w.source, wsrc = prevSrc, cfg = w.config, r = cfg + 1;
+        for (boolean active = true, locals = true;;) {
+            boolean busy = false, scan = false;
+            if (locals) {  // run local tasks before (re)polling
+                locals = false;
+                for (ForkJoinTask<?> u; (u = w.nextLocalTask(cfg)) != null;)
+                    u.doExec();
+            }
+            WorkQueue[] qs = queues;
+            int n = (qs == null) ? 0 : qs.length;
+            for (int i = n; i > 0; --i, ++r) {
+                int j, b, cap; WorkQueue q; ForkJoinTask<?>[] a;
+                if ((q = qs[j = (n - 1) & r]) != null && q != w &&
+                    (a = q.array) != null && (cap = a.length) > 0) {
+                    int k = (cap - 1) & (b = q.base);
+                    int nextBase = b + 1, src = j | SRC;
+                    ForkJoinTask<?> t = WorkQueue.getSlot(a, k);
+                    if (q.base != b)
+                        busy = scan = true;
+                    else if (t != null) {
+                        busy = scan = true;
+                        if (!active) {    // increment before taking
+                            active = true;
+                            getAndAddCtl(RC_UNIT);
+                        }
+                        if (WorkQueue.casSlotToNull(a, k, t)) {
+                            q.base = nextBase;
+                            w.source = src;
+                            t.doExec();
+                            w.source = wsrc = prevSrc;
+                            locals = true;
+                        }
+                        break;
+                    }
+                    else if (!busy) {
+                        if (q.top != b || a[nextBase & (cap - 1)] != null)
+                            busy = scan = true;
+                        else if (q.source != QUIET && q.phase >= 0)
+                            busy = true;
+                    }
+                }
+            }
+            VarHandle.acquireFence();
+            if (!scan && queues == qs) {
+                boolean interrupted;
+                if (!busy) {
+                    w.source = prevSrc;
+                    if (!active)
+                        getAndAddCtl(RC_UNIT);
+                    return 1;
+                }
+                if (wsrc != QUIET)
+                    w.source = wsrc = QUIET;
+                if (active) {                 // decrement
+                    active = false;
+                    parkTime = 0L;
+                    getAndAddCtl(RC_MASK & -RC_UNIT);
+                }
+                else if (parkTime == 0L) {
+                    parkTime = 1L << 10; // initially about 1 usec
+                    Thread.yield();
+                }
+                else if ((interrupted = interruptible && Thread.interrupted()) ||
+                         System.nanoTime() - startTime > nanos) {
+                    getAndAddCtl(RC_UNIT);
+                    return interrupted ? -1 : 0;
+                }
+                else {
+                    LockSupport.parkNanos(this, parkTime);
+                    if (parkTime < nanos >>> 8 && parkTime < 1L << 20)
+                        parkTime <<= 1;  // max sleep approx 1 sec or 1% nanos
+                }
+            }
+        }
+    }
+
+    /**
+     * Helps quiesce from external caller until done, interrupted, or timeout
+     *
+     * @param nanos max wait time (Long.MAX_VALUE if effectively untimed)
+     * @param interruptible true if return on interrupt
+     * @return positive if quiescent, negative if interrupted, else 0
+     */
+    final int externalHelpQuiescePool(long nanos, boolean interruptible) {
+        for (long startTime = System.nanoTime(), parkTime = 0L;;) {
+            ForkJoinTask<?> t;
+            if ((t = pollScan(false)) != null) {
+                t.doExec();
+                parkTime = 0L;
+            }
+            else if (canStop())
+                return 1;
+            else if (parkTime == 0L) {
+                parkTime = 1L << 10;
+                Thread.yield();
+            }
+            else if ((System.nanoTime() - startTime) > nanos)
+                return 0;
+            else if (interruptible && Thread.interrupted())
+                return -1;
+            else {
+                LockSupport.parkNanos(this, parkTime);
+                if (parkTime < nanos >>> 8 && parkTime < 1L << 20)
+                    parkTime <<= 1;
+            }
+        }
+    }
+
+    /**
+     * Gets and removes a local or stolen task for the given worker.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
+        ForkJoinTask<?> t;
+        if (w == null || (t = w.nextLocalTask(w.config)) == null)
+            t = pollScan(false);
+        return t;
+    }
+
+    // External operations
+
+    /**
+     * Finds and locks a WorkQueue for an external submitter, or
+     * returns null if shutdown or terminating.
+     */
+    final WorkQueue submissionQueue() {
+        int r;
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();           // initialize caller's probe
+            r = ThreadLocalRandom.getProbe();
+        }
+        for (int id = r << 1;;) {                    // even indices only
+            int md = mode, n, i; WorkQueue q; ReentrantLock lock;
+            WorkQueue[] qs = queues;
+            if ((md & SHUTDOWN) != 0 || qs == null || (n = qs.length) <= 0)
+                return null;
+            else if ((q = qs[i = (n - 1) & id]) == null) {
+                if ((lock = registrationLock) != null) {
+                    WorkQueue w = new WorkQueue(id | SRC);
+                    lock.lock();                    // install under lock
+                    if (qs[i] == null)
+                        qs[i] = w;                  // else lost race; discard
+                    lock.unlock();
+                }
+            }
+            else if (!q.tryLock())                  // move and restart
+                id = (r = ThreadLocalRandom.advanceProbe(r)) << 1;
+            else
+                return q;
+        }
+    }
+
+    /**
+     * Adds the given task to an external submission queue, or throws
+     * exception if shutdown or terminating.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        WorkQueue q;
+        if ((q = submissionQueue()) == null)
+            throw new RejectedExecutionException(); // shutdown or disabled
+        else if (q.lockedPush(task))
+            signalWork();
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread wt; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (q = (wt = (ForkJoinWorkerThread)t).workQueue) != null &&
+            wt.pool == this)
+            q.push(task, this);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread that has
+     * possibly ever submitted a common pool task (nonzero probe), or
+     * null if none.
+     */
+    static WorkQueue commonQueue() {
+        ForkJoinPool p; WorkQueue[] qs;
+        int r = ThreadLocalRandom.getProbe(), n;
+        return ((p = common) != null && (qs = p.queues) != null &&
+                (n = qs.length) > 0 && r != 0) ?
+            qs[(n - 1) & (r << 1)] : null;
+    }
+
+    /**
+     * Returns queue for an external thread, if one exists
+     */
+    final WorkQueue externalQueue() {
+        WorkQueue[] qs;
+        int r = ThreadLocalRandom.getProbe(), n;
+        return ((qs = queues) != null && (n = qs.length) > 0 && r != 0) ?
+            qs[(n - 1) & (r << 1)] : null;
+    }
+
+    /**
+     * If the given executor is a ForkJoinPool, poll and execute
+     * AsynchronousCompletionTasks from worker's queue until none are
+     * available or blocker is released.
+     */
+    static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
+        WorkQueue w = null; Thread t; ForkJoinWorkerThread wt;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            if ((wt = (ForkJoinWorkerThread)t).pool == e)
+                w = wt.workQueue;
+        }
+        else if (e instanceof ForkJoinPool)
+            w = ((ForkJoinPool)e).externalQueue();
+        if (w != null)
+            w.helpAsyncBlocker(blocker);
+    }
+
+    /**
+     * Returns 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.  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.
+     */
+    static int getSurplusQueuedTaskCount() {
+        Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (pool = (wt = (ForkJoinWorkerThread)t).pool) != null &&
+            (q = wt.workQueue) != null) {
+            int p = pool.mode & SMASK;
+            int a = p + (int)(pool.ctl >> RC_SHIFT);
+            int n = q.top - q.base;
+            return n - (a > (p >>>= 1) ? 0 :
+                        a > (p >>>= 1) ? 1 :
+                        a > (p >>>= 1) ? 2 :
+                        a > (p >>>= 1) ? 4 :
+                        8);
+        }
+        return 0;
+    }
+
+    // Termination
+
+    /**
+     * Possibly initiates and/or completes termination.
+     *
+     * @param now if true, unconditionally terminate, else only
+     * if no work and no active workers
+     * @param enable if true, terminate when next possible
+     * @return true if terminating or terminated
+     */
+    private boolean tryTerminate(boolean now, boolean enable) {
+        int md; // try to set SHUTDOWN, then STOP, then help terminate
+        if (((md = mode) & SHUTDOWN) == 0) {
+            if (!enable)
+                return false;
+            md = getAndBitwiseOrMode(SHUTDOWN);
+        }
+        if ((md & STOP) == 0) {
+            if (!now && !canStop())
+                return false;
+            md = getAndBitwiseOrMode(STOP);
+        }
+        for (boolean rescan = true;;) { // repeat until no changes
+            boolean changed = false;
+            for (ForkJoinTask<?> t; (t = pollScan(false)) != null; ) {
+                changed = true;
+                ForkJoinTask.cancelIgnoringExceptions(t); // help cancel
+            }
+            WorkQueue[] qs; int n; WorkQueue q; Thread thread;
+            if ((qs = queues) != null && (n = qs.length) > 0) {
+                for (int j = 1; j < n; j += 2) { // unblock other workers
+                    if ((q = qs[j]) != null && (thread = q.owner) != null &&
+                        !thread.isInterrupted()) {
+                        changed = true;
+                        try {
+                            thread.interrupt();
+                        } catch (Throwable ignore) {
+                        }
+                    }
+                }
+            }
+            ReentrantLock lock; Condition cond; // signal when no workers
+            if (((md = mode) & TERMINATED) == 0 &&
+                (md & SMASK) + (short)(ctl >>> TC_SHIFT) <= 0 &&
+                (getAndBitwiseOrMode(TERMINATED) & TERMINATED) == 0 &&
+                (lock = registrationLock) != null) {
+                lock.lock();
+                if ((cond = termination) != null)
+                    cond.signalAll();
+                lock.unlock();
+            }
+            if (changed)
+                rescan = true;
+            else if (rescan)
+                rescan = false;
+            else
+                break;
+        }
+        return true;
+    }
+
+    // Exported methods
+
+    // Constructors
+
+    /**
+     * Creates a {@code ForkJoinPool} with parallelism equal to {@link
+     * java.lang.Runtime#availableProcessors}, using defaults for all
+     * other parameters (see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool() {
+        this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
+             defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the indicated parallelism
+     * level, using defaults for all other parameters (see {@link
+     * #ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+     * UncaughtExceptionHandler, boolean, int, int, int, Predicate,
+     * long, TimeUnit)}).
+     *
+     * @param parallelism the parallelism level
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism) {
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters (using
+     * defaults for others -- see {@link #ForkJoinPool(int,
+     * ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean,
+     * int, int, int, Predicate, long, TimeUnit)}).
+     *
+     * @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
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode) {
+        this(parallelism, factory, handler, asyncMode,
+             0, MAX_CAP, 1, null, DEFAULT_KEEPALIVE, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 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}.
+     *
+     * @param corePoolSize the number of threads to keep in the pool
+     * (unless timed out after an elapsed keep-alive). Normally (and
+     * by default) this is the same value as the parallelism level,
+     * but may be set to a larger value to reduce dynamic overhead if
+     * tasks regularly block. Using a smaller value (for example
+     * {@code 0}) has the same effect as the default.
+     *
+     * @param maximumPoolSize the maximum number of threads allowed.
+     * When the maximum is reached, attempts to replace blocked
+     * threads fail.  (However, because creation and termination of
+     * different threads may overlap, and may be managed by the given
+     * thread factory, this value may be transiently exceeded.)  To
+     * arrange the same value as is used by default for the common
+     * pool, use {@code 256} plus the {@code parallelism} level. (By
+     * default, the common pool allows a maximum of 256 spare
+     * threads.)  Using a value (for example {@code
+     * Integer.MAX_VALUE}) larger than the implementation's total
+     * thread limit has the same effect as using this limit (which is
+     * the default).
+     *
+     * @param minimumRunnable the minimum allowed number of core
+     * threads not blocked by a join or {@link ManagedBlocker}.  To
+     * ensure progress, when too few unblocked threads exist and
+     * unexecuted tasks may exist, new threads are constructed, up to
+     * the given maximumPoolSize.  For the default value, use {@code
+     * 1}, that ensures liveness.  A larger value might improve
+     * throughput in the presence of blocked activities, but might
+     * not, due to increased overhead.  A value of zero may be
+     * acceptable when submitted tasks cannot have dependencies
+     * requiring additional threads.
+     *
+     * @param saturate if non-null, a predicate invoked upon attempts
+     * to create more than the maximum total allowed threads.  By
+     * default, when a thread is about to block on a join or {@link
+     * ManagedBlocker}, but cannot be replaced because the
+     * maximumPoolSize would be exceeded, a {@link
+     * RejectedExecutionException} is thrown.  But if this predicate
+     * returns {@code true}, then no exception is thrown, so the pool
+     * continues to operate with fewer than the target number of
+     * runnable threads, which might not ensure progress.
+     *
+     * @param keepAliveTime the elapsed time since last use before
+     * a thread is terminated (and then later replaced if needed).
+     * For the default value, use {@code 60, TimeUnit.SECONDS}.
+     *
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     *
+     * @throws IllegalArgumentException if parallelism is less than or
+     *         equal to zero, or is greater than implementation limit,
+     *         or if maximumPoolSize is less than parallelism,
+     *         of if the keepAliveTime is less than or equal to zero.
+     * @throws NullPointerException if the factory is null
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     * @since 9
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode,
+                        int corePoolSize,
+                        int maximumPoolSize,
+                        int minimumRunnable,
+                        Predicate<? super ForkJoinPool> saturate,
+                        long keepAliveTime,
+                        TimeUnit unit) {
+        checkPermission();
+        int p = parallelism;
+        if (p <= 0 || p > MAX_CAP || p > maximumPoolSize || keepAliveTime <= 0L)
+            throw new IllegalArgumentException();
+        if (factory == null || unit == null)
+            throw new NullPointerException();
+        this.factory = factory;
+        this.ueh = handler;
+        this.saturate = saturate;
+        this.keepAlive = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);
+        int size = 1 << (33 - Integer.numberOfLeadingZeros(p - 1));
+        int corep = Math.min(Math.max(corePoolSize, p), MAX_CAP);
+        int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - p;
+        int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
+        this.bounds = ((minAvail - p) & SMASK) | (maxSpares << SWIDTH);
+        this.mode = p | (asyncMode ? FIFO : 0);
+        this.ctl = ((((long)(-corep) << TC_SHIFT) & TC_MASK) |
+                    (((long)(-p)     << RC_SHIFT) & RC_MASK));
+        this.registrationLock = new ReentrantLock();
+        this.queues = new WorkQueue[size];
+        String pid = Integer.toString(getAndAddPoolIds(1) + 1);
+        this.workerNamePrefix = "ForkJoinPool-" + pid + "-worker-";
+    }
+
+    // helper method for commonPool constructor
+    private static Object newInstanceFromSystemProperty(String property)
+        throws ReflectiveOperationException {
+        String className = System.getProperty(property);
+        return (className == null)
+            ? null
+            : ClassLoader.getSystemClassLoader().loadClass(className)
+            .getConstructor().newInstance();
+    }
+
+    /**
+     * Constructor for common pool using parameters possibly
+     * overridden by system properties
+     */
+    private ForkJoinPool(byte forCommonPoolOnly) {
+        int parallelism = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
+        ForkJoinWorkerThreadFactory fac = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(
+                "java.util.concurrent.ForkJoinPool.common.threadFactory");
+            handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(
+                "java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+        } catch (Exception ignore) {
+        }
+        this.ueh = handler;
+        this.keepAlive = DEFAULT_KEEPALIVE;
+        this.saturate = null;
+        this.workerNamePrefix = null;
+        int p = Math.min(Math.max(parallelism, 0), MAX_CAP), size;
+        this.mode = p;
+        if (p > 0) {
+            size = 1 << (33 - Integer.numberOfLeadingZeros(p - 1));
+            this.bounds = ((1 - p) & SMASK) | (COMMON_MAX_SPARES << SWIDTH);
+            this.ctl = ((((long)(-p) << TC_SHIFT) & TC_MASK) |
+                        (((long)(-p) << RC_SHIFT) & RC_MASK));
+        } else {  // zero min, max, spare counts, 1 slot
+            size = 1;
+            this.bounds = 0;
+            this.ctl = 0L;
+        }
+        this.factory = (fac != null) ? fac :
+            new DefaultCommonPoolForkJoinWorkerThreadFactory();
+        this.queues = new WorkQueue[size];
+        this.registrationLock = new ReentrantLock();
+    }
+
+    /**
+     * Returns the common pool instance. This pool is statically
+     * constructed; its run state is unaffected by attempts to {@link
+     * #shutdown} or {@link #shutdownNow}. However this pool and any
+     * ongoing processing are automatically terminated upon program
+     * {@link System#exit}.  Any program that relies on asynchronous
+     * task processing to complete before program termination should
+     * invoke {@code commonPool().}{@link #awaitQuiescence awaitQuiescence},
+     * before exit.
+     *
+     * @return the common pool instance
+     * @since 1.8
+     */
+    public static ForkJoinPool commonPool() {
+        // assert common != null : "static init error";
+        return common;
+    }
+
+    // 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
+     * @param <T> the type of the task's result
+     * @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) {
+        externalSubmit(task);
+        return task.joinForPoolInvoke(this);
+    }
+
+    /**
+     * 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) {
+        externalSubmit(task);
+    }
+
+    // AbstractExecutorService methods
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public void execute(Runnable task) {
+        externalSubmit((task instanceof ForkJoinTask<?>)
+                       ? (ForkJoinTask<Void>) task // avoid re-wrap
+                       : new ForkJoinTask.RunnableExecuteAction(task));
+    }
+
+    /**
+     * Submits a ForkJoinTask for execution.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @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) {
+        return externalSubmit(task);
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    @Override
+    public <T> ForkJoinTask<T> submit(Callable<T> task) {
+        return externalSubmit(new ForkJoinTask.AdaptedCallable<T>(task));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    @Override
+    public <T> ForkJoinTask<T> submit(Runnable task, T result) {
+        return externalSubmit(new ForkJoinTask.AdaptedRunnable<T>(task, result));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public ForkJoinTask<?> submit(Runnable task) {
+        return externalSubmit((task instanceof ForkJoinTask<?>)
+            ? (ForkJoinTask<Void>) task // avoid re-wrap
+            : new ForkJoinTask.AdaptedRunnableAction(task));
+    }
+
+    /**
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws RejectedExecutionException {@inheritDoc}
+     */
+    @Override
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        try {
+            for (Callable<T> t : tasks) {
+                ForkJoinTask<T> f =
+                    new ForkJoinTask.AdaptedInterruptibleCallable<T>(t);
+                futures.add(f);
+                externalSubmit(f);
+            }
+            for (int i = futures.size() - 1; i >= 0; --i)
+                ((ForkJoinTask<?>)futures.get(i)).awaitPoolInvoke(this);
+            return futures;
+        } catch (Throwable t) {
+            for (Future<T> e : futures)
+                ForkJoinTask.cancelIgnoringExceptions(e);
+            throw t;
+        }
+    }
+
+    @Override
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        try {
+            for (Callable<T> t : tasks) {
+                ForkJoinTask<T> f =
+                    new ForkJoinTask.AdaptedInterruptibleCallable<T>(t);
+                futures.add(f);
+                externalSubmit(f);
+            }
+            long startTime = System.nanoTime(), ns = nanos;
+            boolean timedOut = (ns < 0L);
+            for (int i = futures.size() - 1; i >= 0; --i) {
+                Future<T> f = futures.get(i);
+                if (!f.isDone()) {
+                    if (timedOut)
+                        ForkJoinTask.cancelIgnoringExceptions(f);
+                    else {
+                        ((ForkJoinTask<T>)f).awaitPoolInvoke(this, ns);
+                        if ((ns = nanos - (System.nanoTime() - startTime)) < 0L)
+                            timedOut = true;
+                    }
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            for (Future<T> e : futures)
+                ForkJoinTask.cancelIgnoringExceptions(e);
+            throw t;
+        }
+    }
+
+    // Task to hold results from InvokeAnyTasks
+    static final class InvokeAnyRoot<E> extends ForkJoinTask<E> {
+        private static final long serialVersionUID = 2838392045355241008L;
+        @SuppressWarnings("serial") // Conditionally serializable
+        volatile E result;
+        final AtomicInteger count;  // in case all throw
+        final ForkJoinPool pool;    // to check shutdown while collecting
+        InvokeAnyRoot(int n, ForkJoinPool p) {
+            pool = p;
+            count = new AtomicInteger(n);
+        }
+        final void tryComplete(Callable<E> c) { // called by InvokeAnyTasks
+            Throwable ex = null;
+            boolean failed;
+            if (c == null || Thread.interrupted() ||
+                (pool != null && pool.mode < 0))
+                failed = true;
+            else if (isDone())
+                failed = false;
+            else {
+                try {
+                    complete(c.call());
+                    failed = false;
+                } catch (Throwable tx) {
+                    ex = tx;
+                    failed = true;
+                }
+            }
+            if ((pool != null && pool.mode < 0) ||
+                (failed && count.getAndDecrement() <= 1))
+                trySetThrown(ex != null ? ex : new CancellationException());
+        }
+        public final boolean exec()         { return false; } // never forked
+        public final E getRawResult()       { return result; }
+        public final void setRawResult(E v) { result = v; }
+    }
+
+    // Variant of AdaptedInterruptibleCallable with results in InvokeAnyRoot
+    static final class InvokeAnyTask<E> extends ForkJoinTask<E> {
+        private static final long serialVersionUID = 2838392045355241008L;
+        final InvokeAnyRoot<E> root;
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Callable<E> callable;
+        transient volatile Thread runner;
+        InvokeAnyTask(InvokeAnyRoot<E> root, Callable<E> callable) {
+            this.root = root;
+            this.callable = callable;
+        }
+        public final boolean exec() {
+            Thread.interrupted();
+            runner = Thread.currentThread();
+            root.tryComplete(callable);
+            runner = null;
+            Thread.interrupted();
+            return true;
+        }
+        public final boolean cancel(boolean mayInterruptIfRunning) {
+            Thread t;
+            boolean stat = super.cancel(false);
+            if (mayInterruptIfRunning && (t = runner) != null) {
+                try {
+                    t.interrupt();
+                } catch (Throwable ignore) {
+                }
+            }
+            return stat;
+        }
+        public final void setRawResult(E v) {} // unused
+        public final E getRawResult()       { return null; }
+    }
+
+    @Override
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException {
+        int n = tasks.size();
+        if (n <= 0)
+            throw new IllegalArgumentException();
+        InvokeAnyRoot<T> root = new InvokeAnyRoot<T>(n, this);
+        ArrayList<InvokeAnyTask<T>> fs = new ArrayList<>(n);
+        try {
+            for (Callable<T> c : tasks) {
+                if (c == null)
+                    throw new NullPointerException();
+                InvokeAnyTask<T> f = new InvokeAnyTask<T>(root, c);
+                fs.add(f);
+                externalSubmit(f);
+                if (root.isDone())
+                    break;
+            }
+            return root.getForPoolInvoke(this);
+        } finally {
+            for (InvokeAnyTask<T> f : fs)
+                ForkJoinTask.cancelIgnoringExceptions(f);
+        }
+    }
+
+    @Override
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                           long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
+        int n = tasks.size();
+        if (n <= 0)
+            throw new IllegalArgumentException();
+        InvokeAnyRoot<T> root = new InvokeAnyRoot<T>(n, this);
+        ArrayList<InvokeAnyTask<T>> fs = new ArrayList<>(n);
+        try {
+            for (Callable<T> c : tasks) {
+                if (c == null)
+                    throw new NullPointerException();
+                InvokeAnyTask<T> f = new InvokeAnyTask<T>(root, c);
+                fs.add(f);
+                externalSubmit(f);
+                if (root.isDone())
+                    break;
+            }
+            return root.getForPoolInvoke(this, nanos);
+        } finally {
+            for (InvokeAnyTask<T> f : fs)
+                ForkJoinTask.cancelIgnoringExceptions(f);
+        }
+    }
+
+    /**
+     * 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 UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        return ueh;
+    }
+
+    /**
+     * Returns the targeted parallelism level of this pool.
+     *
+     * @return the targeted parallelism level of this pool
+     */
+    public int getParallelism() {
+        int par = mode & SMASK;
+        return (par > 0) ? par : 1;
+    }
+
+    /**
+     * Returns the targeted parallelism level of the common pool.
+     *
+     * @return the targeted parallelism level of the common pool
+     * @since 1.8
+     */
+    public static int getCommonPoolParallelism() {
+        return COMMON_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 ((mode & SMASK) + (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 (mode & FIFO) != 0;
+    }
+
+    /**
+     * 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() {
+        VarHandle.acquireFence();
+        WorkQueue[] qs; WorkQueue q;
+        int rc = 0;
+        if ((qs = queues) != null) {
+            for (int i = 1; i < qs.length; i += 2) {
+                if ((q = qs[i]) != null && q.isApparentlyUnblocked())
+                    ++rc;
+            }
+        }
+        return rc;
+    }
+
+    /**
+     * 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 = (mode & SMASK) + (int)(ctl >> RC_SHIFT);
+        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 canStop();
+    }
+
+    /**
+     * Returns an estimate of the total number of completed tasks that
+     * were executed by a thread other than their submitter. 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() {
+        long count = stealCount;
+        WorkQueue[] qs; WorkQueue q;
+        if ((qs = queues) != null) {
+            for (int i = 1; i < qs.length; i += 2) {
+                if ((q = qs[i]) != null)
+                    count += (long)q.nsteals & 0xffffffffL;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * 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() {
+        VarHandle.acquireFence();
+        WorkQueue[] qs; WorkQueue q;
+        int count = 0;
+        if ((qs = queues) != null) {
+            for (int i = 1; i < qs.length; i += 2) {
+                if ((q = qs[i]) != null)
+                    count += q.queueSize();
+            }
+        }
+        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() {
+        VarHandle.acquireFence();
+        WorkQueue[] qs; WorkQueue q;
+        int count = 0;
+        if ((qs = queues) != null) {
+            for (int i = 0; i < qs.length; i += 2) {
+                if ((q = qs[i]) != null)
+                    count += q.queueSize();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * 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() {
+        VarHandle.acquireFence();
+        WorkQueue[] qs; WorkQueue q;
+        if ((qs = queues) != null) {
+            for (int i = 0; i < qs.length; i += 2) {
+                if ((q = qs[i]) != null && !q.isEmpty())
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 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() {
+        return pollScan(true);
+    }
+
+    /**
+     * 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;
+        for (ForkJoinTask<?> t; (t = pollScan(false)) != null; ) {
+            c.add(t);
+            ++count;
+        }
+        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() {
+        // Use a single pass through queues to collect counts
+        int md = mode; // read volatile fields first
+        long c = ctl;
+        long st = stealCount;
+        long qt = 0L, ss = 0L; int rc = 0;
+        WorkQueue[] qs; WorkQueue q;
+        if ((qs = queues) != null) {
+            for (int i = 0; i < qs.length; ++i) {
+                if ((q = qs[i]) != null) {
+                    int size = q.queueSize();
+                    if ((i & 1) == 0)
+                        ss += size;
+                    else {
+                        qt += size;
+                        st += (long)q.nsteals & 0xffffffffL;
+                        if (q.isApparentlyUnblocked())
+                            ++rc;
+                    }
+                }
+            }
+        }
+
+        int pc = (md & SMASK);
+        int tc = pc + (short)(c >>> TC_SHIFT);
+        int ac = pc + (int)(c >> RC_SHIFT);
+        if (ac < 0) // ignore transient negative
+            ac = 0;
+        String level = ((md & TERMINATED) != 0 ? "Terminated" :
+                        (md & STOP)       != 0 ? "Terminating" :
+                        (md & SHUTDOWN)   != 0 ? "Shutting down" :
+                        "Running");
+        return super.toString() +
+            "[" + level +
+            ", parallelism = " + pc +
+            ", size = " + tc +
+            ", active = " + ac +
+            ", running = " + rc +
+            ", steals = " + st +
+            ", tasks = " + qt +
+            ", submissions = " + ss +
+            "]";
+    }
+
+    /**
+     * Possibly initiates an orderly shutdown in which previously
+     * submitted tasks are executed, but no new tasks will be
+     * accepted. Invocation has no effect on execution state if this
+     * is the {@link #commonPool()}, and 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.
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public void shutdown() {
+        checkPermission();
+        if (this != common)
+            tryTerminate(false, true);
+    }
+
+    /**
+     * Possibly attempts to cancel and/or stop all tasks, and reject
+     * all subsequently submitted tasks.  Invocation has no effect on
+     * execution state if this is the {@link #commonPool()}, and no
+     * additional effect if already shut down. Otherwise, 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
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public List<Runnable> shutdownNow() {
+        checkPermission();
+        if (this != common)
+            tryTerminate(true, 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() {
+        return (mode & TERMINATED) != 0;
+    }
+
+    /**
+     * 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 I/O,
+     * 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() {
+        return (mode & (STOP | TERMINATED)) == STOP;
+    }
+
+    /**
+     * Returns {@code true} if this pool has been shut down.
+     *
+     * @return {@code true} if this pool has been shut down
+     */
+    public boolean isShutdown() {
+        return (mode & SHUTDOWN) != 0;
+    }
+
+    /**
+     * Blocks until all tasks have completed execution after a
+     * shutdown request, or the timeout occurs, or the current thread
+     * is interrupted, whichever happens first. Because the {@link
+     * #commonPool()} never terminates until program shutdown, when
+     * applied to the common pool, this method is equivalent to {@link
+     * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
+     *
+     * @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 {
+        ReentrantLock lock; Condition cond;
+        long nanos = unit.toNanos(timeout);
+        boolean terminated = false;
+        if (this == common) {
+            Thread t; ForkJoinWorkerThread wt; int q;
+            if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread &&
+                (wt = (ForkJoinWorkerThread)t).pool == this)
+                q = helpQuiescePool(wt.workQueue, nanos, true);
+            else
+                q = externalHelpQuiescePool(nanos, true);
+            if (q < 0)
+                throw new InterruptedException();
+        }
+        else if (!(terminated = ((mode & TERMINATED) != 0)) &&
+                 (lock = registrationLock) != null) {
+            lock.lock();
+            try {
+                if ((cond = termination) == null)
+                    termination = cond = lock.newCondition();
+                while (!(terminated = ((mode & TERMINATED) != 0)) && nanos > 0L)
+                    nanos = cond.awaitNanos(nanos);
+            } finally {
+                lock.unlock();
+            }
+        }
+        return terminated;
+    }
+
+    /**
+     * If called by a ForkJoinTask operating in this pool, equivalent
+     * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise,
+     * waits and/or attempts to assist performing tasks until this
+     * pool {@link #isQuiescent} or the indicated timeout elapses.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if quiescent; {@code false} if the
+     * timeout elapsed.
+     */
+    public boolean awaitQuiescence(long timeout, TimeUnit unit) {
+        Thread t; ForkJoinWorkerThread wt; int q;
+        long nanos = unit.toNanos(timeout);
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread &&
+            (wt = (ForkJoinWorkerThread)t).pool == this)
+            q = helpQuiescePool(wt.workQueue, nanos, false);
+        else
+            q = externalHelpQuiescePool(nanos, false);
+        return (q > 0);
+    }
+
+    /**
+     * Interface for extending managed parallelism for tasks running
+     * in {@link ForkJoinPool}s.
+     *
+     * <p>A {@code ManagedBlocker} provides two methods.  Method
+     * {@link #isReleasable} must return {@code true} if blocking is
+     * not necessary. Method {@link #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(ManagedBlocker)}.  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. Neither method is invoked after a prior invocation
+     * of {@code isReleasable} or {@code block} returns {@code true}.
+     *
+     * <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.
+         * @return {@code true} if blocking is unnecessary
+         */
+        boolean isReleasable();
+    }
+
+    /**
+     * Runs the given possibly blocking task.  When {@linkplain
+     * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this
+     * method possibly arranges for a spare thread to be activated if
+     * necessary to ensure sufficient parallelism while the current
+     * thread is blocked in {@link ManagedBlocker#block blocker.block()}.
+     *
+     * <p>This method repeatedly calls {@code blocker.isReleasable()} and
+     * {@code blocker.block()} until either method returns {@code true}.
+     * Every call to {@code blocker.block()} is preceded by a call to
+     * {@code blocker.isReleasable()} that returned {@code false}.
+     *
+     * <p>If not running in a ForkJoinPool, this method is
+     * behaviorally equivalent to
+     * <pre> {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     break;}</pre>
+     *
+     * If running in a ForkJoinPool, the pool may first be expanded to
+     * ensure sufficient parallelism available during the call to
+     * {@code blocker.block()}.
+     *
+     * @param blocker the blocker task
+     * @throws InterruptedException if {@code blocker.block()} did so
+     */
+    public static void managedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        Thread t; ForkJoinPool p;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread &&
+            (p = ((ForkJoinWorkerThread)t).pool) != null)
+            p.compensatedBlock(blocker);
+        else
+            unmanagedBlock(blocker);
+    }
+
+    /** ManagedBlock for ForkJoinWorkerThreads */
+    private void compensatedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        if (blocker == null) throw new NullPointerException();
+        for (;;) {
+            int comp; boolean done;
+            long c = ctl;
+            if (blocker.isReleasable())
+                break;
+            if ((comp = tryCompensate(c)) >= 0) {
+                long post = (comp == 0) ? 0L : RC_UNIT;
+                try {
+                    done = blocker.block();
+                } finally {
+                    getAndAddCtl(post);
+                }
+                if (done)
+                    break;
+            }
+        }
+    }
+
+    /** ManagedBlock for external threads */
+    private static void unmanagedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        if (blocker == null) throw new NullPointerException();
+        do {} while (!blocker.isReleasable() && !blocker.block());
+    }
+
+    // AbstractExecutorService.newTaskFor overrides rely on
+    // undocumented fact that ForkJoinTask.adapt returns ForkJoinTasks
+    // that also implement RunnableFuture.
+
+    @Override
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new ForkJoinTask.AdaptedRunnable<T>(runnable, value);
+    }
+
+    @Override
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new ForkJoinTask.AdaptedCallable<T>(callable);
+    }
+
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
+            MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
+            THREADIDS = l.findVarHandle(ForkJoinPool.class, "threadIds", int.class);
+            POOLIDS = l.findStaticVarHandle(ForkJoinPool.class, "poolIds", int.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+
+        int commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
+        try {
+            String p = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.maximumSpares");
+            if (p != null)
+                commonMaxSpares = Integer.parseInt(p);
+        } catch (Exception ignore) {}
+        COMMON_MAX_SPARES = commonMaxSpares;
+
+        defaultForkJoinWorkerThreadFactory =
+            new DefaultForkJoinWorkerThreadFactory();
+        modifyThreadPermission = new RuntimePermission("modifyThread");
+        @SuppressWarnings("removal")
+        ForkJoinPool tmp = AccessController.doPrivileged(new PrivilegedAction<>() {
+            public ForkJoinPool run() {
+                return new ForkJoinPool((byte)0); }});
+        common = tmp;
+
+        COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
+    }
+}
diff --git a/android-35/java/util/concurrent/ForkJoinTask.java b/android-35/java/util/concurrent/ForkJoinTask.java
new file mode 100644
index 0000000..cc2ff75
--- /dev/null
+++ b/android-35/java/util/concurrent/ForkJoinTask.java
@@ -0,0 +1,1599 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+import java.util.concurrent.locks.LockSupport;
+
+// BEGIN android-note
+// removed java 9 code
+// END android-note
+
+/**
+ * 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 it is
+ * explicitly submitted to a {@link ForkJoinPool}, or, if not already
+ * engaged in a ForkJoin computation, commenced in the {@link
+ * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * related methods.  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 main 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
+ * ideally 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. Subdividable tasks should also
+ * not perform blocking I/O, and should ideally access variables that
+ * are completely independent of those accessed by other running
+ * tasks. These guidelines are loosely 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>It is possible to define and use ForkJoinTasks that may block,
+ * but doing so requires three further considerations: (1) Completion
+ * of few if any <em>other</em> tasks should be dependent on a task
+ * that blocks on external synchronization or I/O. Event-style async
+ * tasks that are never joined (for example, those subclassing {@link
+ * CountedCompleter}) often fall into this category.  (2) To minimize
+ * resource impact, tasks should be small; ideally performing only the
+ * (possibly) blocking action. (3) Unless the {@link
+ * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
+ * blocked tasks is known to be less than the pool's {@link
+ * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
+ * enough threads will be available to ensure progress or good
+ * performance.
+ *
+ * <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>In the most typical usages, a fork-join pair act like a call
+ * (fork) and return (join) from a parallel recursive function. As is
+ * the case with other forms of recursive calls, returns (joins)
+ * should be performed innermost-first. For example, {@code a.fork();
+ * b.fork(); b.join(); a.join();} is likely to be substantially more
+ * efficient than joining {@code a} before {@code b}.
+ *
+ * <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 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 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 most computations that do not return results,
+ * {@link RecursiveTask} for those that do, and {@link
+ * CountedCompleter} for those in which completed actions trigger
+ * other actions.  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.
+ *
+ * <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. To support such usages, a
+ * ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
+ * value using {@link #setForkJoinTaskTag} or {@link
+ * #compareAndSetForkJoinTaskTag} and checked using {@link
+ * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * these {@code protected} methods or tags for any purpose, but they
+ * may be of use in the construction of specialized subclasses.  For
+ * example, parallel graph traversals can use the supplied methods to
+ * avoid revisiting nodes/tasks that have already been processed.
+ * (Method names for tagging are bulky in part to encourage definition
+ * of methods that reflect their usage patterns.)
+ *
+ * <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
+ * @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.
+     *
+     * Revision notes: The use of "Aux" field replaces previous
+     * reliance on a table to hold exceptions and synchronized blocks
+     * and monitors to wait for completion.
+     */
+
+    /**
+     * Nodes for threads waiting for completion, or holding a thrown
+     * exception (never both). Waiting threads prepend nodes
+     * Treiber-stack-style.  Signallers detach and unpark
+     * waiters. Cancelled waiters try to unsplice.
+     */
+    static final class Aux {
+        final Thread thread;
+        final Throwable ex;  // null if a waiter
+        Aux next;            // accessed only via memory-acquire chains
+        Aux(Thread thread, Throwable ex) {
+            this.thread = thread;
+            this.ex = ex;
+        }
+        final boolean casNext(Aux c, Aux v) { // used only in cancellation
+            return NEXT.compareAndSet(this, c, v);
+        }
+        private static final VarHandle NEXT;
+        static {
+            try {
+                NEXT = MethodHandles.lookup()
+                    .findVarHandle(Aux.class, "next", Aux.class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+    }
+
+    /*
+     * The status field holds bits packed into a single int to ensure
+     * atomicity.  Status is initially zero, and takes on nonnegative
+     * values until completed, upon which it holds (sign bit) DONE,
+     * possibly with ABNORMAL (cancelled or exceptional) and THROWN
+     * (in which case an exception has been stored). A value of
+     * ABNORMAL without DONE signifies an interrupted wait.  These
+     * control bits occupy only (some of) the upper half (16 bits) of
+     * status field. The lower bits are used for user-defined tags.
+     */
+    private static final int DONE         = 1 << 31; // must be negative
+    private static final int ABNORMAL     = 1 << 16;
+    private static final int THROWN       = 1 << 17;
+    private static final int SMASK        = 0xffff;  // short bits for tags
+    private static final int UNCOMPENSATE = 1 << 16; // helpJoin return sentinel
+
+    // Fields
+    volatile int status;                // accessed directly by pool and workers
+    private transient volatile Aux aux; // either waiters or thrown Exception
+
+    // Support for atomic operations
+    private static final VarHandle STATUS;
+    private static final VarHandle AUX;
+    private int getAndBitwiseOrStatus(int v) {
+        return (int)STATUS.getAndBitwiseOr(this, v);
+    }
+    private boolean casStatus(int c, int v) {
+        return STATUS.compareAndSet(this, c, v);
+    }
+    private boolean casAux(Aux c, Aux v) {
+        return AUX.compareAndSet(this, c, v);
+    }
+
+    /** Removes and unparks waiters */
+    private void signalWaiters() {
+        for (Aux a; (a = aux) != null && a.ex == null; ) {
+            if (casAux(a, null)) {             // detach entire list
+                for (Thread t; a != null; a = a.next) {
+                    if ((t = a.thread) != Thread.currentThread() && t != null)
+                        LockSupport.unpark(t); // don't self-signal
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * Sets DONE status and wakes up threads waiting to join this task.
+     * @return status on exit
+     */
+    private int setDone() {
+        int s = getAndBitwiseOrStatus(DONE) | DONE;
+        signalWaiters();
+        return s;
+    }
+
+    /**
+     * Sets ABNORMAL DONE status unless already done, and wakes up threads
+     * waiting to join this task.
+     * @return status on exit
+     */
+    private int trySetCancelled() {
+        int s;
+        do {} while ((s = status) >= 0 && !casStatus(s, s |= (DONE | ABNORMAL)));
+        signalWaiters();
+        return s;
+    }
+
+    /**
+     * Records exception and sets ABNORMAL THROWN DONE status unless
+     * already done, and wakes up threads waiting to join this task.
+     * If losing a race with setDone or trySetCancelled, the exception
+     * may be recorded but not reported.
+     *
+     * @return status on exit
+     */
+    final int trySetThrown(Throwable ex) {
+        Aux h = new Aux(Thread.currentThread(), ex), p = null;
+        boolean installed = false;
+        int s;
+        while ((s = status) >= 0) {
+            Aux a;
+            if (!installed && ((a = aux) == null || a.ex == null) &&
+                (installed = casAux(a, h)))
+                p = a; // list of waiters replaced by h
+            if (installed && casStatus(s, s |= (DONE | ABNORMAL | THROWN)))
+                break;
+        }
+        for (; p != null; p = p.next)
+            LockSupport.unpark(p.thread);
+        return s;
+    }
+
+    /**
+     * Records exception unless already done. Overridable in subclasses.
+     *
+     * @return status on exit
+     */
+    int trySetException(Throwable ex) {
+        return trySetThrown(ex);
+    }
+
+    /**
+     * Constructor for subclasses to call.
+     */
+    public ForkJoinTask() {}
+
+    static boolean isExceptionalStatus(int s) {  // needed by subclasses
+        return (s & THROWN) != 0;
+    }
+
+    /**
+     * Unless done, calls exec and records status if completed, but
+     * doesn't wait for completion otherwise.
+     *
+     * @return status on exit from this method
+     */
+    final int doExec() {
+        int s; boolean completed;
+        if ((s = status) >= 0) {
+            try {
+                completed = exec();
+            } catch (Throwable rex) {
+                s = trySetException(rex);
+                completed = false;
+            }
+            if (completed)
+                s = setDone();
+        }
+        return s;
+    }
+
+    /**
+     * Helps and/or waits for completion from join, get, or invoke;
+     * called from either internal or external threads.
+     *
+     * @param pool if nonnull, known submitted pool, else assumes current pool
+     * @param ran true if task known to have been exec'd
+     * @param interruptible true if park interruptibly when external
+     * @param timed true if use timed wait
+     * @param nanos if timed, timeout value
+     * @return ABNORMAL if interrupted, else status on exit
+     */
+    private int awaitDone(ForkJoinPool pool, boolean ran,
+                          boolean interruptible, boolean timed,
+                          long nanos) {
+        ForkJoinPool p; boolean internal; int s; Thread t;
+        ForkJoinPool.WorkQueue q = null;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+            p = wt.pool;
+            if (pool == null)
+                pool = p;
+            if (internal = (pool == p))
+                q = wt.workQueue;
+        }
+        else {
+            internal = false;
+            p = ForkJoinPool.common;
+            if (pool == null)
+                pool = p;
+            if (pool == p && p != null)
+                q = p.externalQueue();
+        }
+        if (interruptible && Thread.interrupted())
+            return ABNORMAL;
+        if ((s = status) < 0)
+            return s;
+        long deadline = 0L;
+        if (timed) {
+            if (nanos <= 0L)
+                return 0;
+            else if ((deadline = nanos + System.nanoTime()) == 0L)
+                deadline = 1L;
+        }
+        boolean uncompensate = false;
+        if (q != null && p != null) {  // try helping
+            // help even in timed mode if pool has no parallelism
+            boolean canHelp = !timed || (p.mode & SMASK) == 0;
+            if (canHelp) {
+                if ((this instanceof CountedCompleter) &&
+                    (s = p.helpComplete(this, q, internal)) < 0)
+                    return s;
+                if (!ran && ((!internal && q.externalTryUnpush(this)) ||
+                             q.tryRemove(this, internal)) && (s = doExec()) < 0)
+                    return s;
+            }
+            if (internal) {
+                if ((s = p.helpJoin(this, q, canHelp)) < 0)
+                    return s;
+                if (s == UNCOMPENSATE)
+                    uncompensate = true;
+            }
+        }
+        // block until done or cancelled wait
+        boolean interrupted = false, queued = false;
+        boolean parked = false, fail = false;
+        Aux node = null;
+        while ((s = status) >= 0) {
+            Aux a; long ns;
+            if (fail || (fail = (pool != null && pool.mode < 0)))
+                casStatus(s, s | (DONE | ABNORMAL)); // try to cancel
+            else if (parked && Thread.interrupted()) {
+                if (interruptible) {
+                    s = ABNORMAL;
+                    break;
+                }
+                interrupted = true;
+            }
+            else if (queued) {
+                if (deadline != 0L) {
+                    if ((ns = deadline - System.nanoTime()) <= 0L)
+                        break;
+                    LockSupport.parkNanos(ns);
+                }
+                else
+                    LockSupport.park();
+                parked = true;
+            }
+            else if (node != null) {
+                if ((a = aux) != null && a.ex != null)
+                    Thread.onSpinWait();     // exception in progress
+                else if (queued = casAux(node.next = a, node))
+                    LockSupport.setCurrentBlocker(this);
+            }
+            else {
+                try {
+                    node = new Aux(Thread.currentThread(), null);
+                } catch (Throwable ex) {     // cannot create
+                    fail = true;
+                }
+            }
+        }
+        if (pool != null && uncompensate)
+            pool.uncompensate();
+
+        if (queued) {
+            LockSupport.setCurrentBlocker(null);
+            if (s >= 0) { // cancellation similar to AbstractQueuedSynchronizer
+                outer: for (Aux a; (a = aux) != null && a.ex == null; ) {
+                    for (Aux trail = null;;) {
+                        Aux next = a.next;
+                        if (a == node) {
+                            if (trail != null)
+                                trail.casNext(trail, next);
+                            else if (casAux(a, next))
+                                break outer; // cannot be re-encountered
+                            break;           // restart
+                        } else {
+                            trail = a;
+                            if ((a = next) == null)
+                                break outer;
+                        }
+                    }
+                }
+            }
+            else {
+                signalWaiters();             // help clean or signal
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Cancels, ignoring any exceptions thrown by cancel.  Cancel is
+     * spec'ed not to throw any exceptions, but if it does anyway, we
+     * have no recourse, so guard against this case.
+     */
+    static final void cancelIgnoringExceptions(Future<?> t) {
+        if (t != null) {
+            try {
+                t.cancel(true);
+            } catch (Throwable ignore) {
+            }
+        }
+    }
+
+    /**
+     * Returns a rethrowable exception for this 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() {
+        Throwable ex; Aux a;
+        if ((a = aux) == null)
+            ex = null;
+        else if ((ex = a.ex) != null && a.thread != Thread.currentThread()) {
+            try {
+                Constructor<?> noArgCtor = null, oneArgCtor = null;
+                for (Constructor<?> c : ex.getClass().getConstructors()) {
+                    Class<?>[] ps = c.getParameterTypes();
+                    if (ps.length == 0)
+                        noArgCtor = c;
+                    else if (ps.length == 1 && ps[0] == Throwable.class) {
+                        oneArgCtor = c;
+                        break;
+                    }
+                }
+                if (oneArgCtor != null)
+                    ex = (Throwable)oneArgCtor.newInstance(ex);
+                else if (noArgCtor != null) {
+                    Throwable rx = (Throwable)noArgCtor.newInstance();
+                    rx.initCause(ex);
+                    ex = rx;
+                }
+            } catch (Exception ignore) {
+            }
+        }
+        return ex;
+    }
+
+    /**
+     * Returns exception associated with the given status, or null if none.
+     */
+    private Throwable getException(int s) {
+        Throwable ex = null;
+        if ((s & ABNORMAL) != 0 &&
+            ((s & THROWN) == 0 || (ex = getThrowableException()) == null))
+            ex = new CancellationException();
+        return ex;
+    }
+
+    /**
+     * Throws exception associated with the given status, or
+     * CancellationException if none recorded.
+     */
+    private void reportException(int s) {
+        ForkJoinTask.<RuntimeException>uncheckedThrow(
+            (s & THROWN) != 0 ? getThrowableException() : null);
+    }
+
+    /**
+     * Throws exception for (timed or untimed) get, wrapping if
+     * necessary in an ExecutionException.
+     */
+    private void reportExecutionException(int s) {
+        Throwable ex = null;
+        if (s == ABNORMAL)
+            ex = new InterruptedException();
+        else if (s >= 0)
+            ex = new TimeoutException();
+        else if ((s & THROWN) != 0 && (ex = getThrowableException()) != null)
+            ex = new ExecutionException(ex);
+        ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
+    }
+
+    /**
+     * A version of "sneaky throw" to relay exceptions in other
+     * contexts.
+     */
+    static void rethrow(Throwable ex) {
+        ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
+    }
+
+    /**
+     * The sneaky part of sneaky throw, relying on generics
+     * limitations to evade compiler complaints about rethrowing
+     * unchecked exceptions. If argument null, throws
+     * CancellationException.
+     */
+    @SuppressWarnings("unchecked") static <T extends Throwable>
+    void uncheckedThrow(Throwable t) throws T {
+        if (t == null)
+            t = new CancellationException();
+        throw (T)t; // rely on vacuous cast
+    }
+
+    // public methods
+
+    /**
+     * Arranges to asynchronously execute this task in the pool the
+     * current task is running in, if applicable, or using the {@link
+     * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}.  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}.
+     *
+     * @return {@code this}, to simplify usage
+     */
+    public final ForkJoinTask<V> fork() {
+        Thread t; ForkJoinWorkerThread w;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            (w = (ForkJoinWorkerThread)t).workQueue.push(this, w.pool);
+        else
+            ForkJoinPool.common.externalPush(this);
+        return this;
+    }
+
+    /**
+     * Returns the result of the computation when it
+     * {@linkplain #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() {
+        int s;
+        if ((s = status) >= 0)
+            s = awaitDone(null, false, false, false, 0L);
+        if ((s & ABNORMAL) != 0)
+            reportException(s);
+        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() {
+        int s;
+        if ((s = doExec()) >= 0)
+            s = awaitDone(null, true, false, false, 0L);
+        if ((s & ABNORMAL) != 0)
+            reportException(s);
+        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.
+     *
+     * @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) {
+        int s1, s2;
+        if (t1 == null || t2 == null)
+            throw new NullPointerException();
+        t2.fork();
+        if ((s1 = t1.doExec()) >= 0)
+            s1 = t1.awaitDone(null, true, false, false, 0L);
+        if ((s1 & ABNORMAL) != 0) {
+            cancelIgnoringExceptions(t2);
+            t1.reportException(s1);
+        }
+        else if (((s2 = t2.awaitDone(null, false, false, false, 0L)) & ABNORMAL) != 0)
+            t2.reportException(s2);
+    }
+
+    /**
+     * 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.
+     *
+     * @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;
+            if ((t = tasks[i]) == null) {
+                ex = new NullPointerException();
+                break;
+            }
+            if (i == 0) {
+                int s;
+                if ((s = t.doExec()) >= 0)
+                    s = t.awaitDone(null, true, false, false, 0L);
+                if ((s & ABNORMAL) != 0)
+                    ex = t.getException(s);
+                break;
+            }
+            t.fork();
+        }
+        if (ex == null) {
+            for (int i = 1; i <= last; ++i) {
+                ForkJoinTask<?> t;
+                if ((t = tasks[i]) != null) {
+                    int s;
+                    if ((s = t.status) >= 0)
+                        s = t.awaitDone(null, false, false, false, 0L);
+                    if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
+                        break;
+                }
+            }
+        }
+        if (ex != null) {
+            for (int i = 1; i <= last; ++i)
+                cancelIgnoringExceptions(tasks[i]);
+            rethrow(ex);
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the 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<?>[0]));
+            return tasks;
+        }
+        @SuppressWarnings("unchecked")
+        List<? extends ForkJoinTask<?>> ts =
+            (List<? extends ForkJoinTask<?>>) tasks;
+        Throwable ex = null;
+        int last = ts.size() - 1;  // nearly same as array version
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t;
+            if ((t = ts.get(i)) == null) {
+                ex = new NullPointerException();
+                break;
+            }
+            if (i == 0) {
+                int s;
+                if ((s = t.doExec()) >= 0)
+                    s = t.awaitDone(null, true, false, false, 0L);
+                if ((s & ABNORMAL) != 0)
+                    ex = t.getException(s);
+                break;
+            }
+            t.fork();
+        }
+        if (ex == null) {
+            for (int i = 1; i <= last; ++i) {
+                ForkJoinTask<?> t;
+                if ((t = ts.get(i)) != null) {
+                    int s;
+                    if ((s = t.status) >= 0)
+                        s = t.awaitDone(null, false, false, false, 0L);
+                    if ((s & ABNORMAL) != 0 && (ex = t.getException(s)) != null)
+                        break;
+                }
+            }
+        }
+        if (ex != null) {
+            for (int i = 1; i <= last; ++i)
+                cancelIgnoringExceptions(ts.get(i));
+            rethrow(ex);
+        }
+        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(Throwable)}.
+     *
+     * @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 (trySetCancelled() & (ABNORMAL | THROWN)) == ABNORMAL;
+    }
+
+    public final boolean isDone() {
+        return status < 0;
+    }
+
+    public final boolean isCancelled() {
+        return (status & (ABNORMAL | THROWN)) == ABNORMAL;
+    }
+
+    /**
+     * 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 & ABNORMAL) != 0;
+    }
+
+    /**
+     * 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 & (DONE | ABNORMAL)) == DONE;
+    }
+
+    /**
+     * 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() {
+        return getException(status);
+    }
+
+    /**
+     * 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) {
+        trySetException((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) {
+            trySetException(rex);
+            return;
+        }
+        setDone();
+    }
+
+    /**
+     * Completes this task normally without setting a value. The most
+     * recent value established by {@link #setRawResult} (or {@code
+     * null} by default) will be returned as the result of subsequent
+     * invocations of {@code join} and related operations.
+     *
+     * @since 1.8
+     */
+    public final void quietlyComplete() {
+        setDone();
+    }
+
+    /**
+     * 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 = awaitDone(null, false, true, false, 0L);
+        if ((s & ABNORMAL) != 0)
+            reportExecutionException(s);
+        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 {
+        long nanos = unit.toNanos(timeout);
+        int s = awaitDone(null, false, true, true, nanos);
+        if (s >= 0 || (s & ABNORMAL) != 0)
+            reportExecutionException(s);
+        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() {
+        if (status >= 0)
+            awaitDone(null, false, false, false, 0L);
+    }
+
+
+    /**
+     * Commences performing this task and awaits its completion if
+     * necessary, without returning its result or throwing its
+     * exception.
+     */
+    public final void quietlyInvoke() {
+        if (doExec() >= 0)
+            awaitDone(null, true, false, false, 0L);
+    }
+
+    // Versions of join/get for pool.invoke* methods that use external,
+    // possibly-non-commonPool submits
+
+    final void awaitPoolInvoke(ForkJoinPool pool) {
+        awaitDone(pool, false, false, false, 0L);
+    }
+    final void awaitPoolInvoke(ForkJoinPool pool, long nanos) {
+        awaitDone(pool, false, true, true, nanos);
+    }
+    final V joinForPoolInvoke(ForkJoinPool pool) {
+        int s = awaitDone(pool, false, false, false, 0L);
+        if ((s & ABNORMAL) != 0)
+            reportException(s);
+        return getRawResult();
+    }
+    final V getForPoolInvoke(ForkJoinPool pool)
+        throws InterruptedException, ExecutionException {
+        int s = awaitDone(pool, false, true, false, 0L);
+        if ((s & ABNORMAL) != 0)
+            reportExecutionException(s);
+        return getRawResult();
+    }
+    final V getForPoolInvoke(ForkJoinPool pool, long nanos)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        int s = awaitDone(pool, false, true, true, nanos);
+        if (s >= 0 || (s & ABNORMAL) != 0)
+            reportExecutionException(s);
+        return getRawResult();
+    }
+
+    /**
+     * Possibly executes tasks until the pool hosting the current task
+     * {@linkplain 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.
+     */
+    public static void helpQuiesce() {
+        Thread t; ForkJoinWorkerThread w; ForkJoinPool p;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread &&
+            (p = (w = (ForkJoinWorkerThread)t).pool) != null)
+            p.helpQuiescePool(w.workQueue, Long.MAX_VALUE, false);
+        else
+            ForkJoinPool.common.externalHelpQuiescePool(Long.MAX_VALUE, false);
+    }
+
+    /**
+     * 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() {
+        aux = null;
+        status = 0;
+    }
+
+    /**
+     * Returns the pool hosting the current thread, or {@code null}
+     * if the current thread is executing outside of any ForkJoinPool.
+     *
+     * <p>This method returns {@code null} if and only if {@link
+     * #inForkJoinPool} returns {@code false}.
+     *
+     * @return the pool, or {@code null} if none
+     */
+    public static ForkJoinPool getPool() {
+        Thread t;
+        return (((t = Thread.currentThread()) 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 (but is not guaranteed to) 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.
+     *
+     * @return {@code true} if unforked
+     */
+    public boolean tryUnfork() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            ? (q = ((ForkJoinWorkerThread)t).workQueue) != null
+               && q.tryUnpush(this)
+            : (q = ForkJoinPool.commonQueue()) != null
+               && q.externalTryUnpush(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.
+     *
+     * @return the number of tasks
+     */
+    public static int getQueuedTaskCount() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonQueue();
+        return (q == null) ? 0 : q.queueSize();
+    }
+
+    /**
+     * 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, or zero if this thread is not
+     * operating in a ForkJoinPool. 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.
+     *
+     * @return the surplus number of tasks, which may be negative
+     */
+    public static int getSurplusQueuedTaskCount() {
+        return ForkJoinPool.getSurplusQueuedTaskCount();
+    }
+
+    // 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 and returns
+     * true if, upon return from this method, this task is guaranteed
+     * to have completed. This method may return false otherwise, to
+     * indicate that this task is not necessarily complete (or is not
+     * known to be complete), for example in asynchronous actions that
+     * require explicit invocations of completion methods. This method
+     * may also throw an (unchecked) exception to indicate abnormal
+     * exit. This method is designed to support extensions, and should
+     * not in general be called otherwise.
+     *
+     * @return {@code true} if this task is known to have 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.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> peekNextLocalTask() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonQueue();
+        return (q == null) ? null : q.peek();
+    }
+
+    /**
+     * Unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if the
+     * current thread is operating in a ForkJoinPool.  This method is
+     * designed primarily to support extensions, and is unlikely to be
+     * useful otherwise.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollNextLocalTask() {
+        Thread t;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                ((ForkJoinWorkerThread)t).workQueue.nextLocalTask() : null);
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * 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.
+     *
+     * @return a task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollTask() {
+        Thread t; ForkJoinWorkerThread w;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                (w = (ForkJoinWorkerThread)t).pool.nextTaskFor(w.workQueue) :
+                null);
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, a task externally
+     * submitted to the pool, if one is available. Availability may be
+     * transient, so a {@code null} result does not necessarily imply
+     * quiescence of the pool.  This method is designed primarily to
+     * support extensions, and is unlikely to be useful otherwise.
+     *
+     * @return a task, or {@code null} if none are available
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    protected static ForkJoinTask<?> pollSubmission() {
+        Thread t;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                ((ForkJoinWorkerThread)t).pool.pollSubmission() : null);
+    }
+
+    // tag operations
+
+    /**
+     * Returns the tag for this task.
+     *
+     * @return the tag for this task
+     * @since 1.8
+     */
+    public final short getForkJoinTaskTag() {
+        return (short)status;
+    }
+
+    /**
+     * Atomically sets the tag value for this task and returns the old value.
+     *
+     * @param newValue the new tag value
+     * @return the previous value of the tag
+     * @since 1.8
+     */
+    public final short setForkJoinTaskTag(short newValue) {
+        for (int s;;) {
+            if (casStatus(s = status, (s & ~SMASK) | (newValue & SMASK)))
+                return (short)s;
+        }
+    }
+
+    /**
+     * Atomically conditionally sets the tag value for this task.
+     * Among other applications, tags can be used as visit markers
+     * in tasks operating on graphs, as in methods that check: {@code
+     * if (task.compareAndSetForkJoinTaskTag((short)0, (short)1))}
+     * before processing, otherwise exiting because the node has
+     * already been visited.
+     *
+     * @param expect the expected tag value
+     * @param update the new tag value
+     * @return {@code true} if successful; i.e., the current value was
+     * equal to {@code expect} and was changed to {@code update}.
+     * @since 1.8
+     */
+    public final boolean compareAndSetForkJoinTaskTag(short expect, short update) {
+        for (int s;;) {
+            if ((short)(s = status) != expect)
+                return false;
+            if (casStatus(s, (s & ~SMASK) | (update & SMASK)))
+                return true;
+        }
+    }
+
+    /**
+     * Adapter 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> {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Runnable runnable;
+        @SuppressWarnings("serial") // Conditionally serializable
+        T result;
+        AdaptedRunnable(Runnable runnable, T result) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+            this.result = result; // OK to set this even before completion
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables without results.
+     */
+    static final class AdaptedRunnableAction extends ForkJoinTask<Void>
+        implements RunnableFuture<Void> {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Runnable runnable;
+        AdaptedRunnableAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables in which failure forces worker exception.
+     */
+    static final class RunnableExecuteAction extends ForkJoinTask<Void> {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Runnable runnable;
+        RunnableExecuteAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        int trySetException(Throwable ex) { // if a handler, invoke it
+            int s; Thread t; java.lang.Thread.UncaughtExceptionHandler h;
+            if (isExceptionalStatus(s = trySetThrown(ex)) &&
+                (h = ((t = Thread.currentThread()).
+                      getUncaughtExceptionHandler())) != null) {
+                try {
+                    h.uncaughtException(t, ex);
+                } catch (Throwable ignore) {
+                }
+            }
+            return s;
+        }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Callables.
+     */
+    static final class AdaptedCallable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Callable<? extends T> callable;
+        @SuppressWarnings("serial") // Conditionally serializable
+        T result;
+        AdaptedCallable(Callable<? extends T> callable) {
+            if (callable == null) throw new NullPointerException();
+            this.callable = callable;
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() {
+            try {
+                result = callable.call();
+                return true;
+            } catch (RuntimeException rex) {
+                throw rex;
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + callable + "]";
+        }
+        private static final long serialVersionUID = 2838392045355241008L;
+    }
+
+    static final class AdaptedInterruptibleCallable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        @SuppressWarnings("serial") // Conditionally serializable
+        final Callable<? extends T> callable;
+        @SuppressWarnings("serial") // Conditionally serializable
+        transient volatile Thread runner;
+        T result;
+        AdaptedInterruptibleCallable(Callable<? extends T> callable) {
+            if (callable == null) throw new NullPointerException();
+            this.callable = callable;
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() {
+            Thread.interrupted();
+            runner = Thread.currentThread();
+            try {
+                if (!isDone()) // recheck
+                    result = callable.call();
+                return true;
+            } catch (RuntimeException rex) {
+                throw rex;
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            } finally {
+                runner = null;
+                Thread.interrupted();
+            }
+        }
+        public final void run() { invoke(); }
+        public final boolean cancel(boolean mayInterruptIfRunning) {
+            Thread t;
+            boolean stat = super.cancel(false);
+            if (mayInterruptIfRunning && (t = runner) != null) {
+                try {
+                    t.interrupt();
+                } catch (Throwable ignore) {
+                }
+            }
+            return stat;
+        }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + callable + "]";
+        }
+        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 AdaptedRunnableAction(runnable);
+    }
+
+    /**
+     * 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
+     * @param <T> the type of the result
+     * @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
+     * @param <T> the type of the callable's result
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
+        return new AdaptedCallable<T>(callable);
+    }
+
+    /**
+     * 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}.  Additionally,
+     * invocations of {@code cancel} with {@code mayInterruptIfRunning
+     * true} will attempt to interrupt the thread performing the task.
+     *
+     * @param callable the callable action
+     * @param <T> the type of the callable's result
+     * @return the task
+     *
+     * @since 17
+     */
+    // adaptInterruptible deferred to its own independent change
+    // https://bugs.openjdk.java.net/browse/JDK-8246587
+    /* TODO: public */ private static <T> ForkJoinTask<T> adaptInterruptible(Callable<? extends T> callable) {
+        return new AdaptedInterruptibleCallable<T>(callable);
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -7721805057305804111L;
+
+    /**
+     * Saves this task to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData the current run status and the exception thrown
+     * during execution, or {@code null} if none
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        Aux a;
+        s.defaultWriteObject();
+        s.writeObject((a = aux) == null ? null : a.ex);
+    }
+
+    /**
+     * Reconstitutes this task from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        Object ex = s.readObject();
+        if (ex != null)
+            trySetThrown((Throwable)ex);
+    }
+
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
+            AUX = l.findVarHandle(ForkJoinTask.class, "aux", Aux.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/ForkJoinWorkerThread.java b/android-35/java/util/concurrent/ForkJoinWorkerThread.java
new file mode 100644
index 0000000..b76e0f6
--- /dev/null
+++ b/android-35/java/util/concurrent/ForkJoinWorkerThread.java
@@ -0,0 +1,213 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * 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
+ * {@linkplain ForkJoinPool#ForkJoinPool(int, ForkJoinWorkerThreadFactory,
+ * UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit)
+ * use it} in a {@code ForkJoinPool}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class ForkJoinWorkerThread extends Thread {
+    /*
+     * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
+     * ForkJoinTasks. For explanation, see the internal documentation
+     * of class ForkJoinPool.
+     *
+     * This class just maintains links to its pool and WorkQueue.
+     */
+
+    final ForkJoinPool pool;                // the pool this thread works in
+    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
+
+    /**
+     * Full nonpublic constructor.
+     */
+    ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool,
+                         boolean useSystemClassLoader, boolean isInnocuous) {
+        super(group, null, pool.nextWorkerThreadName(), 0L);
+        UncaughtExceptionHandler handler = (this.pool = pool).ueh;
+        this.workQueue = new ForkJoinPool.WorkQueue(this, isInnocuous);
+        super.setDaemon(true);
+        if (handler != null)
+            super.setUncaughtExceptionHandler(handler);
+        if (useSystemClassLoader)
+            super.setContextClassLoader(ClassLoader.getSystemClassLoader());
+    }
+
+    /**
+     * Creates a ForkJoinWorkerThread operating in the given thread group and
+     * pool.
+     *
+     * @param group if non-null, the thread group for this thread
+     * @param pool the pool this thread works in
+     * @throws NullPointerException if pool is null
+     */
+    /* TODO: protected */ ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool) {
+        this(group, pool, false, false);
+    }
+
+    /**
+     * 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) {
+        this(null, pool, false, false);
+    }
+
+    /**
+     * Returns the pool hosting this thread.
+     *
+     * @return the pool
+     */
+    public ForkJoinPool getPool() {
+        return pool;
+    }
+
+    /**
+     * Returns the unique index number of this thread in its pool.
+     * The returned value ranges from zero to the maximum number of
+     * threads (minus one) that may exist in the pool, and does not
+     * change during the lifetime of the thread.  This method may be
+     * useful for applications that track status or collect results
+     * per-worker-thread rather than per-task.
+     *
+     * @return the index number
+     */
+    public int getPoolIndex() {
+        return workQueue.getPoolIndex();
+    }
+
+    /**
+     * 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() {
+    }
+
+    /**
+     * 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) {
+    }
+
+    /**
+     * 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;
+        ForkJoinPool p = pool;
+        ForkJoinPool.WorkQueue w = workQueue;
+        if (p != null && w != null) {   // skip on failed initialization
+            try {
+                p.registerWorker(w);
+                onStart();
+                p.runWorker(w);
+            } catch (Throwable ex) {
+                exception = ex;
+            } finally {
+                try {
+                    onTermination(exception);
+                } catch (Throwable ex) {
+                    if (exception == null)
+                        exception = ex;
+                } finally {
+                    p.deregisterWorker(this, exception);
+                }
+            }
+        }
+    }
+
+    /**
+     * A worker thread that has no permissions, is not a member of any
+     * user-defined ThreadGroup, uses the system class loader as
+     * thread context class loader, and erases all ThreadLocals after
+     * running each top-level task.
+     */
+    static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
+        /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
+        @SuppressWarnings("removal")
+        private static final ThreadGroup innocuousThreadGroup =
+            AccessController.doPrivileged(new PrivilegedAction<>() {
+                public ThreadGroup run() {
+                    ThreadGroup group = Thread.currentThread().getThreadGroup();
+                    for (ThreadGroup p; (p = group.getParent()) != null; )
+                        group = p;
+                    return new ThreadGroup(
+                        group, "InnocuousForkJoinWorkerThreadGroup");
+                }});
+
+        InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
+            super(innocuousThreadGroup, pool, true, true);
+        }
+
+        @Override // to silently fail
+        public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
+
+        @Override // paranoically
+        public void setContextClassLoader(ClassLoader cl) {
+            if (cl != null && ClassLoader.getSystemClassLoader() != cl)
+                throw new SecurityException("setContextClassLoader");
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/Future.java b/android-35/java/util/concurrent/Future.java
new file mode 100644
index 0000000..ebbf14d
--- /dev/null
+++ b/android-35/java/util/concurrent/Future.java
@@ -0,0 +1,164 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@code Future} represents the result of an asynchronous
+ * computation.  Methods are provided to check if the computation is
+ * complete, to wait for its completion, and to retrieve the result of
+ * the computation.  The result can only be retrieved using method
+ * {@code get} when the computation has completed, blocking if
+ * necessary until it is ready.  Cancellation is performed by the
+ * {@code cancel} method.  Additional methods are provided to
+ * determine if the task completed normally or was cancelled. Once a
+ * computation has completed, the computation cannot be cancelled.
+ * If you would like to use a {@code Future} for the sake
+ * of cancellability but not provide a usable result, you can
+ * declare types of the form {@code Future<?>} and
+ * return {@code null} as a result of the underlying task.
+ *
+ * <p><b>Sample Usage</b> (Note that the following classes are all
+ * made-up.)
+ *
+ * <pre> {@code
+ * interface ArchiveSearcher { String search(String target); }
+ * class App {
+ *   ExecutorService executor = ...;
+ *   ArchiveSearcher searcher = ...;
+ *   void showSearch(String target) throws InterruptedException {
+ *     Callable<String> task = () -> searcher.search(target);
+ *     Future<String> future = executor.submit(task);
+ *     displayOtherThings(); // do other things while searching
+ *     try {
+ *       displayText(future.get()); // use future
+ *     } catch (ExecutionException ex) { cleanup(); return; }
+ *   }
+ * }}</pre>
+ *
+ * The {@link FutureTask} class is an implementation of {@code Future} that
+ * implements {@code Runnable}, and so may be executed by an {@code Executor}.
+ * For example, the above construction with {@code submit} could be replaced by:
+ * <pre> {@code
+ * FutureTask<String> future = new FutureTask<>(task);
+ * executor.execute(future);}</pre>
+ *
+ * <p>Memory consistency effects: Actions taken by the asynchronous computation
+ * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
+ * actions following the corresponding {@code Future.get()} in another thread.
+ *
+ * @see FutureTask
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface Future<V> {
+
+    /**
+     * Attempts to cancel execution of this task.  This method has no
+     * effect if the task is already completed or cancelled, or could
+     * not be cancelled for some other reason.  Otherwise, if this
+     * task has not started when {@code cancel} is called, this task
+     * should never run.  If the task has already started, then the
+     * {@code mayInterruptIfRunning} parameter determines whether the
+     * thread executing this task (when known by the implementation)
+     * is interrupted in an attempt to stop the task.
+     *
+     * <p>The return value from this method does not necessarily
+     * indicate whether the task is now cancelled; use {@link
+     * #isCancelled}.
+     *
+     * @param mayInterruptIfRunning {@code true} if the thread
+     * executing this task should be interrupted (if the thread is
+     * known to the implementation); otherwise, in-progress tasks are
+     * allowed to complete
+     * @return {@code false} if the task could not be cancelled,
+     * typically because it has already completed; {@code true}
+     * otherwise. If two or more threads cause a task to be cancelled,
+     * then at least one of them returns {@code true}. Implementations
+     * may provide stronger guarantees.
+     */
+    boolean cancel(boolean mayInterruptIfRunning);
+
+    /**
+     * Returns {@code true} if this task was cancelled before it completed
+     * normally.
+     *
+     * @return {@code true} if this task was cancelled before it completed
+     */
+    boolean isCancelled();
+
+    /**
+     * Returns {@code true} if this task completed.
+     *
+     * Completion may be due to normal termination, an exception, or
+     * cancellation -- in all of these cases, this method will return
+     * {@code true}.
+     *
+     * @return {@code true} if this task completed
+     */
+    boolean isDone();
+
+    /**
+     * 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 was interrupted
+     * while waiting
+     */
+    V get() throws InterruptedException, ExecutionException;
+
+    /**
+     * 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 was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/android-35/java/util/concurrent/FutureTask.java b/android-35/java/util/concurrent/FutureTask.java
new file mode 100644
index 0000000..4263944
--- /dev/null
+++ b/android-35/java/util/concurrent/FutureTask.java
@@ -0,0 +1,542 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+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 {@code get}
+ * methods will block if the computation has not yet completed.  Once
+ * the computation has completed, the computation cannot be restarted
+ * or cancelled (unless the computation is invoked using
+ * {@link #runAndReset}).
+ *
+ * <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
+ * {@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 {@code get} methods
+ */
+public class FutureTask<V> implements RunnableFuture<V> {
+    /*
+     * 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.
+     */
+
+    /**
+     * 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
+     */
+    @SuppressWarnings("unchecked")
+    private V report(int s) throws ExecutionException {
+        Object x = outcome;
+        if (s == NORMAL)
+            return (V)x;
+        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 the callable is null
+     */
+    public FutureTask(Callable<V> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        this.callable = callable;
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    /**
+     * 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
+     * @param result the result to return on successful completion. If
+     * you don't need a particular result, consider using
+     * constructions of the form:
+     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
+     * @throws NullPointerException if the runnable is null
+     */
+    public FutureTask(Runnable runnable, V result) {
+        this.callable = Executors.callable(runnable, result);
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    public boolean isCancelled() {
+        return state >= CANCELLED;
+    }
+
+    public boolean isDone() {
+        return state != NEW;
+    }
+
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (!(state == NEW && STATE.compareAndSet
+              (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+            return false;
+        try {    // in case call to interrupt throws exception
+            if (mayInterruptIfRunning) {
+                try {
+                    Thread t = runner;
+                    if (t != null)
+                        t.interrupt();
+                } finally { // final state
+                    STATE.setRelease(this, INTERRUPTED);
+                }
+            }
+        } finally {
+            finishCompletion();
+        }
+        return true;
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get() throws InterruptedException, ExecutionException {
+        int s = state;
+        if (s <= COMPLETING)
+            s = awaitDone(false, 0L);
+        return report(s);
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        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
+     * {@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
+     * implementation of this method to determine whether this task
+     * has been cancelled.
+     */
+    protected void done() { }
+
+    /**
+     * Sets the result of this future to the given value unless
+     * this future has already been set or has been cancelled.
+     *
+     * <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) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
+            outcome = v;
+            STATE.setRelease(this, NORMAL); // final state
+            finishCompletion();
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * <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) {
+        if (STATE.compareAndSet(this, NEW, COMPLETING)) {
+            outcome = t;
+            STATE.setRelease(this, EXCEPTIONAL); // final state
+            finishCompletion();
+        }
+    }
+
+    public void run() {
+        if (state != NEW ||
+            !RUNNER.compareAndSet(this, 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
+     * computation encounters an exception or is cancelled.  This is
+     * designed for use with tasks that intrinsically execute more
+     * than once.
+     *
+     * @return {@code true} if successfully run and reset
+     */
+    protected boolean runAndReset() {
+        if (state != NEW ||
+            !RUNNER.compareAndSet(this, 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;
+    }
+
+    /**
+     * Ensures that any interrupt from a possible cancel(true) is only
+     * delivered to a task while in run or runAndReset.
+     */
+    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
+
+        // assert state == INTERRUPTED;
+
+        // 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();
+    }
+
+    /**
+     * 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(); }
+    }
+
+    /**
+     * 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 (WAITERS.weakCompareAndSet(this, 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;
+                }
+                break;
+            }
+        }
+
+        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 or at timeout
+     */
+    private int awaitDone(boolean timed, long nanos)
+        throws InterruptedException {
+        // The code below is very delicate, to achieve these goals:
+        // - call nanoTime exactly once for each call to park
+        // - if nanos <= 0L, return promptly without allocation or nanoTime
+        // - if nanos == Long.MIN_VALUE, don't underflow
+        // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
+        //   and we suffer a spurious wakeup, we will do no worse than
+        //   to park-spin for a while
+        long startTime = 0L;    // Special value 0L means not yet parked
+        WaitNode q = null;
+        boolean queued = false;
+        for (;;) {
+            int s = state;
+            if (s > COMPLETING) {
+                if (q != null)
+                    q.thread = null;
+                return s;
+            }
+            else if (s == COMPLETING)
+                // We may have already promised (via isDone) that we are done
+                // so never return empty-handed or throw InterruptedException
+                Thread.yield();
+            else if (Thread.interrupted()) {
+                removeWaiter(q);
+                throw new InterruptedException();
+            }
+            else if (q == null) {
+                if (timed && nanos <= 0L)
+                    return s;
+                q = new WaitNode();
+            }
+            else if (!queued)
+                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
+            else if (timed) {
+                final long parkNanos;
+                if (startTime == 0L) { // first time
+                    startTime = System.nanoTime();
+                    if (startTime == 0L)
+                        startTime = 1L;
+                    parkNanos = nanos;
+                } else {
+                    long elapsed = System.nanoTime() - startTime;
+                    if (elapsed >= nanos) {
+                        removeWaiter(q);
+                        return state;
+                    }
+                    parkNanos = nanos - elapsed;
+                }
+                // nanoTime may be slow; recheck before parking
+                if (state < COMPLETING)
+                    LockSupport.parkNanos(this, parkNanos);
+            }
+            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 (!WAITERS.compareAndSet(this, q, s))
+                        continue retry;
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * Returns a string representation of this FutureTask.
+     *
+     * @implSpec
+     * The default implementation returns a string identifying this
+     * FutureTask, as well as its completion state.  The state, in
+     * brackets, contains one of the strings {@code "Completed Normally"},
+     * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
+     * "Not completed"}.
+     *
+     * @return a string representation of this FutureTask
+     */
+    public String toString() {
+        final String status;
+        switch (state) {
+        case NORMAL:
+            status = "[Completed normally]";
+            break;
+        case EXCEPTIONAL:
+            status = "[Completed exceptionally: " + outcome + "]";
+            break;
+        case CANCELLED:
+        case INTERRUPTING:
+        case INTERRUPTED:
+            status = "[Cancelled]";
+            break;
+        default:
+            // BEGIN Android-changed: recursion risk building string (b/241297967)
+            /*
+            final Callable<?> callable = this.callable;
+            status = (callable == null)
+                ? "[Not completed]"
+                : "[Not completed, task = " + callable + "]";
+            */
+            status = "[Not completed]";
+            // END Android-changed: recursion risk building string (b/241297967)
+        }
+        return super.toString() + status;
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    private static final VarHandle RUNNER;
+    private static final VarHandle WAITERS;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(FutureTask.class, "state", int.class);
+            RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
+            WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+}
diff --git a/android-35/java/util/concurrent/Helpers.java b/android-35/java/util/concurrent/Helpers.java
new file mode 100644
index 0000000..369da0e
--- /dev/null
+++ b/android-35/java/util/concurrent/Helpers.java
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz 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;
+
+/** Shared implementation code for java.util.concurrent. */
+class Helpers {
+    private Helpers() {}                // non-instantiable
+
+    /**
+     * An implementation of Collection.toString() suitable for classes
+     * with locks.  Instead of holding a lock for the entire duration of
+     * toString(), or acquiring a lock for each call to Iterator.next(),
+     * we hold the lock only during the call to toArray() (less
+     * disruptive to other threads accessing the collection) and follows
+     * the maxim "Never call foreign code while holding a lock".
+     */
+    static String collectionToString(Collection<?> c) {
+        final Object[] a = c.toArray();
+        final int size = a.length;
+        if (size == 0)
+            return "[]";
+        int charLength = 0;
+
+        // Replace every array element with its string representation
+        for (int i = 0; i < size; i++) {
+            Object e = a[i];
+            // Extreme compatibility with AbstractCollection.toString()
+            String s = (e == c) ? "(this Collection)" : objectToString(e);
+            a[i] = s;
+            charLength += s.length();
+        }
+
+        return toString(a, size, charLength);
+    }
+
+    /**
+     * Like Arrays.toString(), but caller guarantees that size > 0,
+     * each element with index 0 <= i < size is a non-null String,
+     * and charLength is the sum of the lengths of the input Strings.
+     */
+    static String toString(Object[] a, int size, int charLength) {
+        // assert a != null;
+        // assert size > 0;
+
+        // Copy each string into a perfectly sized char[]
+        // Length of [ , , , ] == 2 * size
+        final char[] chars = new char[charLength + 2 * size];
+        chars[0] = '[';
+        int j = 1;
+        for (int i = 0; i < size; i++) {
+            if (i > 0) {
+                chars[j++] = ',';
+                chars[j++] = ' ';
+            }
+            String s = (String) a[i];
+            int len = s.length();
+            s.getChars(0, len, chars, j);
+            j += len;
+        }
+        chars[j] = ']';
+        // assert j == chars.length - 1;
+        return new String(chars);
+    }
+
+    /** Optimized form of: key + "=" + val */
+    static String mapEntryToString(Object key, Object val) {
+        final String k, v;
+        final int klen, vlen;
+        final char[] chars =
+            new char[(klen = (k = objectToString(key)).length()) +
+                     (vlen = (v = objectToString(val)).length()) + 1];
+        k.getChars(0, klen, chars, 0);
+        chars[klen] = '=';
+        v.getChars(0, vlen, chars, klen + 1);
+        return new String(chars);
+    }
+
+    private static String objectToString(Object x) {
+        // Extreme compatibility with StringBuilder.append(null)
+        String s;
+        return (x == null || (s = x.toString()) == null) ? "null" : s;
+    }
+}
diff --git a/android-35/java/util/concurrent/LinkedBlockingDeque.java b/android-35/java/util/concurrent/LinkedBlockingDeque.java
new file mode 100644
index 0000000..926b4b8
--- /dev/null
+++ b/android-35/java/util/concurrent/LinkedBlockingDeque.java
@@ -0,0 +1,1465 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
+ * linked nodes.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * deque above capacity.
+ *
+ * <p>Most operations run in constant time (ignoring time spent
+ * blocking).  Exceptions include {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link
+ * #removeLastOccurrence removeLastOccurrence}, {@link #contains
+ * contains}, {@link #iterator iterator.remove()}, and the bulk
+ * operations, all of which run in linear time.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author  Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public class LinkedBlockingDeque<E>
+    extends AbstractQueue<E>
+    implements BlockingDeque<E>, java.io.Serializable {
+
+    /*
+     * Implemented as a simple doubly-linked list protected by a
+     * single lock and using conditions to manage blocking.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to jump to "first" (for next links)
+     * or "last" (for prev links).
+     */
+
+    /*
+     * We have "diamond" multiple interface/abstract class inheritance
+     * here, and that introduces ambiguities. Often we want the
+     * BlockingDeque javadoc combined with the AbstractQueue
+     * implementation, so a lot of method specs are duplicated here.
+     */
+
+    private static final long serialVersionUID = -387911632671998426L;
+
+    /** Doubly-linked list node class */
+    static final class Node<E> {
+        /**
+         * The item, or null if this node has been removed.
+         */
+        E item;
+
+        /**
+         * One of:
+         * - the real predecessor Node
+         * - this Node, meaning the predecessor is tail
+         * - null, meaning there is no predecessor
+         */
+        Node<E> prev;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head
+         * - null, meaning there is no successor
+         */
+        Node<E> next;
+
+        Node(E x) {
+            item = x;
+        }
+    }
+
+    /**
+     * Pointer to first node.
+     * Invariant: (first == null && last == null) ||
+     *            (first.prev == null && first.item != null)
+     */
+    transient Node<E> first;
+
+    /**
+     * Pointer to last node.
+     * Invariant: (first == null && last == null) ||
+     *            (last.next == null && last.item != null)
+     */
+    transient Node<E> last;
+
+    /** Number of items in the deque */
+    private transient int count;
+
+    /** Maximum number of items in the deque */
+    private final int capacity;
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock = new ReentrantLock();
+
+    /** Condition for waiting takes */
+    @SuppressWarnings("serial") // Classes implementing Condition may be serializable.
+    private final Condition notEmpty = lock.newCondition();
+
+    /** Condition for waiting puts */
+    @SuppressWarnings("serial") // Classes implementing Condition may be serializable.
+    private final Condition notFull = lock.newCondition();
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingDeque() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this deque
+     * @throws IllegalArgumentException if {@code capacity} is less than 1
+     */
+    public LinkedBlockingDeque(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}, 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 LinkedBlockingDeque(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        addAll(c);
+    }
+
+
+    // Basic linking and unlinking operations, called only while holding lock
+
+    /**
+     * Links node as first element, or returns false if full.
+     */
+    private boolean linkFirst(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> f = first;
+        node.next = f;
+        first = node;
+        if (last == null)
+            last = node;
+        else
+            f.prev = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Links node as last element, or returns false if full.
+     */
+    private boolean linkLast(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> l = last;
+        node.prev = l;
+        last = node;
+        if (first == null)
+            first = node;
+        else
+            l.next = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Removes and returns first element, or null if empty.
+     */
+    private E unlinkFirst() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> f = first;
+        if (f == null)
+            return null;
+        Node<E> n = f.next;
+        E item = f.item;
+        f.item = null;
+        f.next = f; // help GC
+        first = n;
+        if (n == null)
+            last = null;
+        else
+            n.prev = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Removes and returns last element, or null if empty.
+     */
+    private E unlinkLast() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> l = last;
+        if (l == null)
+            return null;
+        Node<E> p = l.prev;
+        E item = l.item;
+        l.item = null;
+        l.prev = l; // help GC
+        last = p;
+        if (p == null)
+            first = null;
+        else
+            p.next = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Unlinks x.
+     */
+    void unlink(Node<E> x) {
+        // assert lock.isHeldByCurrentThread();
+        // assert x.item != null;
+        Node<E> p = x.prev;
+        Node<E> n = x.next;
+        if (p == null) {
+            unlinkFirst();
+        } else if (n == null) {
+            unlinkLast();
+        } else {
+            p.next = n;
+            n.prev = p;
+            x.item = null;
+            // Don't mess with x's links.  They may still be in use by
+            // an iterator.
+            --count;
+            notFull.signal();
+        }
+    }
+
+    // BlockingDeque methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void addFirst(E e) {
+        if (!offerFirst(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException  {@inheritDoc}
+     */
+    public void addLast(E e) {
+        if (!offerLast(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerFirst(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkFirst(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerLast(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkLast(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putFirst(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkFirst(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putLast(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkLast(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkFirst(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkLast(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E x = pollFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E x = pollLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E pollFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkFirst();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkLast();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeFirst() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeLast() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        E x = peekFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        E x = peekLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E peekFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (first == null) ? null : first.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peekLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (last == null) ? null : last.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeFirstOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = last; p != null; p = p.prev) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // BlockingQueue methods
+
+    /**
+     * 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(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        putLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return offerLast(e, timeout, unit);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     * This method differs from {@link #poll() poll()} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    public E poll() {
+        return pollFirst();
+    }
+
+    public E take() throws InterruptedException {
+        return takeFirst();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return pollFirst(timeout, unit);
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek() peek()} only in that
+     * it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    public E peek() {
+        return peekFirst();
+    }
+
+    /**
+     * Returns the number of additional elements that this deque can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this deque
+     * less the current {@code size} of this deque.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return capacity - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            for (int i = 0; i < n; i++) {
+                c.add(first.item);   // In this order, in case add() throws.
+                unlinkFirst();
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // Stack methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    // Collection methods
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this deque, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a deque to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this deque
+     * @throws IllegalStateException if this deque is full
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beg = null, end = null;
+        int n = 0;
+        for (E e : c) {
+            Objects.requireNonNull(e);
+            n++;
+            Node<E> newNode = new Node<E>(e);
+            if (beg == null)
+                beg = end = newNode;
+            else {
+                end.next = newNode;
+                newNode.prev = end;
+                end = newNode;
+            }
+        }
+        if (beg == null)
+            return false;
+
+        // Atomically append the chain at the end
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count + n <= capacity) {
+                beg.prev = last;
+                if (first == null)
+                    first = beg;
+                else
+                    last.next = beg;
+                last = end;
+                count += n;
+                notEmpty.signalAll();
+                return true;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Fall back to historic non-atomic implementation, failing
+        // with IllegalStateException when the capacity is exceeded.
+        return super.addAll(c);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    @SuppressWarnings("unchecked")
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] a = new Object[count];
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the deque fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (a.length < count)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), count);
+
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> f = first; f != null; ) {
+                f.item = null;
+                Node<E> n = f.next;
+                f.prev = null;
+                f.next = null;
+                f = n;
+            }
+            first = last = null;
+            count = 0;
+            notFull.signalAll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Used for any element traversal that is not entirely under lock.
+     * Such traversals must handle both:
+     * - dequeued nodes (p.next == p)
+     * - (possibly multiple) interior removed nodes (p.item == null)
+     */
+    Node<E> succ(Node<E> p) {
+        if (p == (p = p.next))
+            p = first;
+        return p;
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    /**
+     * Base class for LinkedBlockingDeque iterators.
+     */
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * The next node to return in next().
+         */
+        Node<E> next;
+
+        /**
+         * nextItem holds on to item fields because once we claim that
+         * an element exists in hasNext(), we must return item read
+         * under lock even if it was in the process of being removed
+         * when hasNext() was called.
+         */
+        E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> firstNode();
+        abstract Node<E> nextNode(Node<E> n);
+
+        private Node<E> succ(Node<E> p) {
+            if (p == (p = nextNode(p)))
+                p = firstNode();
+            return p;
+        }
+
+        AbstractItr() {
+            // set to initial position
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                if ((next = firstNode()) != null)
+                    nextItem = next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        public E next() {
+            Node<E> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            lastRet = p;
+            E x = nextItem;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                E e = null;
+                for (p = nextNode(p); p != null && (e = p.item) == null; )
+                    p = succ(p);
+                next = p;
+                nextItem = e;
+            } finally {
+                lock.unlock();
+            }
+            return x;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            // A variant of forEachFrom
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = next) == null) return;
+            lastRet = p;
+            next = null;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            final int batchSize = 64;
+            Object[] es = null;
+            int n, len = 1;
+            do {
+                lock.lock();
+                try {
+                    if (es == null) {
+                        p = nextNode(p);
+                        for (Node<E> q = p; q != null; q = succ(q))
+                            if (q.item != null && ++len == batchSize)
+                                break;
+                        es = new Object[len];
+                        es[0] = nextItem;
+                        nextItem = null;
+                        n = 1;
+                    } else
+                        n = 0;
+                    for (; p != null && n < len; p = succ(p))
+                        if ((es[n] = p.item) != null) {
+                            lastRet = p;
+                            n++;
+                        }
+                } finally {
+                    lock.unlock();
+                }
+                for (int i = 0; i < n; i++) {
+                    @SuppressWarnings("unchecked") E e = (E) es[i];
+                    action.accept(e);
+                }
+            } while (n > 0 && p != null);
+        }
+
+        public void remove() {
+            Node<E> n = lastRet;
+            if (n == null)
+                throw new IllegalStateException();
+            lastRet = null;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                if (n.item != null)
+                    unlink(n);
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Itr() {}                        // prevent access constructor creation
+        Node<E> firstNode() { return first; }
+        Node<E> nextNode(Node<E> n) { return n.next; }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        DescendingItr() {}              // prevent access constructor creation
+        Node<E> firstNode() { return last; }
+        Node<E> nextNode(Node<E> n) { return n.prev; }
+    }
+
+    /**
+     * A customized variant of Spliterators.IteratorSpliterator.
+     * Keep this class in sync with (very similar) LBQSpliterator.
+     */
+    private final class LBDSpliterator implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est = size();  // size estimate
+
+        LBDSpliterator() {}
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            if (!exhausted &&
+                ((h = current) != null || (h = first) != null)
+                && h.next != null) {
+                int n = batch = Math.min(batch + 1, MAX_BATCH);
+                Object[] a = new Object[n];
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+                int i = 0;
+                Node<E> p = current;
+                lock.lock();
+                try {
+                    if (p != null || (p = first) != null)
+                        for (; p != null && i < n; p = succ(p))
+                            if ((a[i] = p.item) != null)
+                                i++;
+                } finally {
+                    lock.unlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0)
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+            }
+            return null;
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                E e = null;
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+                lock.lock();
+                try {
+                    Node<E> p;
+                    if ((p = current) != null || (p = first) != null)
+                        do {
+                            e = p.item;
+                            p = succ(p);
+                        } while (e == null && p != null);
+                    if ((current = p) == null)
+                        exhausted = true;
+                } finally {
+                    lock.unlock();
+                }
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                current = null;
+                forEachFrom(action, p);
+            }
+        }
+
+        public int characteristics() {
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBDSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, null);
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, traversal starts at head.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        // Extract batches of elements while holding the lock; then
+        // run the action on the elements while not
+        final ReentrantLock lock = this.lock;
+        final int batchSize = 64;       // max number of elements per batch
+        Object[] es = null;             // container for batch of elements
+        int n, len = 0;
+        do {
+            lock.lock();
+            try {
+                if (es == null) {
+                    if (p == null) p = first;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == batchSize)
+                            break;
+                    es = new Object[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    if ((es[n] = p.item) != null)
+                        n++;
+            } finally {
+                lock.unlock();
+            }
+            for (int i = 0; i < n; i++) {
+                @SuppressWarnings("unchecked") E e = (E) es[i];
+                action.accept(e);
+            }
+        } while (n > 0 && p != null);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        final ReentrantLock lock = this.lock;
+        Node<E> p = null;
+        Node<E>[] nodes = null;
+        int n, len = 0;
+        do {
+            // 1. Extract batch of up to 64 elements while holding the lock.
+            lock.lock();
+            try {
+                if (nodes == null) {  // first batch; initialize
+                    p = first;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == 64)
+                            break;
+                    nodes = (Node<E>[]) new Node<?>[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    nodes[n++] = p;
+            } finally {
+                lock.unlock();
+            }
+
+            // 2. Run the filter on the elements while lock is free.
+            long deathRow = 0L;       // "bitset" of size 64
+            for (int i = 0; i < n; i++) {
+                final E e;
+                if ((e = nodes[i].item) != null && filter.test(e))
+                    deathRow |= 1L << i;
+            }
+
+            // 3. Remove any filtered elements while holding the lock.
+            if (deathRow != 0) {
+                lock.lock();
+                try {
+                    for (int i = 0; i < n; i++) {
+                        final Node<E> q;
+                        if ((deathRow & (1L << i)) != 0L
+                            && (q = nodes[i]).item != null) {
+                            unlink(q);
+                            removed = true;
+                        }
+                        nodes[i] = null; // help GC
+                    }
+                } finally {
+                    lock.unlock();
+                }
+            }
+        } while (n > 0 && p != null);
+        return removed;
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity (int), followed by elements (each an
+     * {@code Object}) in the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            // Write out capacity and any hidden stuff
+            s.defaultWriteObject();
+            // Write out all elements in the proper order.
+            for (Node<E> p = first; p != null; p = p.next)
+                s.writeObject(p.item);
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        count = 0;
+        first = null;
+        last = null;
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked") E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+
+    void checkInvariants() {
+        // assert lock.isHeldByCurrentThread();
+        // Nodes may get self-linked or lose their item, but only
+        // after being unlinked and becoming unreachable from first.
+        for (Node<E> p = first; p != null; p = p.next) {
+            // assert p.next != p;
+            // assert p.item != null;
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/LinkedBlockingQueue.java b/android-35/java/util/concurrent/LinkedBlockingQueue.java
new file mode 100644
index 0000000..a67be9a
--- /dev/null
+++ b/android-35/java/util/concurrent/LinkedBlockingQueue.java
@@ -0,0 +1,1161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
+ * linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * Linked queues typically have higher throughput than array-based queues but
+ * less predictable performance in most concurrent applications.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive queue expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * queue above capacity.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class LinkedBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -6903933977591709194L;
+
+    /*
+     * A variant of the "two lock queue" algorithm.  The putLock gates
+     * entry to put (and offer), and has an associated condition for
+     * waiting puts.  Similarly for the takeLock.  The "count" field
+     * that they both rely on is maintained as an atomic to avoid
+     * needing to get both locks in most cases. Also, to minimize need
+     * for puts to get takeLock and vice-versa, cascading notifies are
+     * used. When a put notices that it has enabled at least one take,
+     * it signals taker. That taker in turn signals others if more
+     * items have been entered since the signal. And symmetrically for
+     * takes signalling puts. Operations such as remove(Object) and
+     * iterators acquire both locks.
+     *
+     * Visibility between writers and readers is provided as follows:
+     *
+     * Whenever an element is enqueued, the putLock is acquired and
+     * count updated.  A subsequent reader guarantees visibility to the
+     * enqueued Node by either acquiring the putLock (via fullyLock)
+     * or by acquiring the takeLock, and then reading n = count.get();
+     * this gives visibility to the first n items.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.next.
+     */
+
+    /**
+     * Linked list node class.
+     */
+    static class Node<E> {
+        E item;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head.next
+         * - null, meaning there is no successor (this is the last node)
+         */
+        Node<E> next;
+
+        Node(E x) { item = x; }
+    }
+
+    /** The capacity bound, or Integer.MAX_VALUE if none */
+    private final int capacity;
+
+    /** Current number of elements */
+    private final AtomicInteger count = new AtomicInteger();
+
+    /**
+     * Head of linked list.
+     * Invariant: head.item == null
+     */
+    transient Node<E> head;
+
+    /**
+     * Tail of linked list.
+     * Invariant: last.next == null
+     */
+    private transient Node<E> last;
+
+    /** Lock held by take, poll, etc */
+    private final ReentrantLock takeLock = new ReentrantLock();
+
+    /** Wait queue for waiting takes */
+    @SuppressWarnings("serial") // Classes implementing Condition may be serializable.
+    private final Condition notEmpty = takeLock.newCondition();
+
+    /** Lock held by put, offer, etc */
+    private final ReentrantLock putLock = new ReentrantLock();
+
+    /** Wait queue for waiting puts */
+    @SuppressWarnings("serial") // Classes implementing Condition may be serializable.
+    private final Condition notFull = putLock.newCondition();
+
+    /**
+     * Signals a waiting take. Called only from put/offer (which do not
+     * otherwise ordinarily lock takeLock.)
+     */
+    private void signalNotEmpty() {
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Signals a waiting put. Called only from take/poll.
+     */
+    private void signalNotFull() {
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    /**
+     * Links node at end of queue.
+     *
+     * @param node the node
+     */
+    private void enqueue(Node<E> node) {
+        // assert putLock.isHeldByCurrentThread();
+        // assert last.next == null;
+        last = last.next = node;
+    }
+
+    /**
+     * Removes a node from head of queue.
+     *
+     * @return the node
+     */
+    private E dequeue() {
+        // assert takeLock.isHeldByCurrentThread();
+        // assert head.item == null;
+        Node<E> h = head;
+        Node<E> first = h.next;
+        h.next = h; // help GC
+        head = first;
+        E x = first.item;
+        first.item = null;
+        return x;
+    }
+
+    /**
+     * Locks to prevent both puts and takes.
+     */
+    void fullyLock() {
+        putLock.lock();
+        takeLock.lock();
+    }
+
+    /**
+     * Unlocks to allow both puts and takes.
+     */
+    void fullyUnlock() {
+        takeLock.unlock();
+        putLock.unlock();
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingQueue() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity} is not greater
+     *         than zero
+     */
+    public LinkedBlockingQueue(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+        last = head = new Node<E>(null);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}, 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 LinkedBlockingQueue(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock(); // Never contended, but necessary for visibility
+        try {
+            int n = 0;
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (n == capacity)
+                    throw new IllegalStateException("Queue full");
+                enqueue(new Node<E>(e));
+                ++n;
+            }
+            count.set(n);
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return count.get();
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        return capacity - count.get();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary for space to become available.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        final int c;
+        final Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            /*
+             * Note that count is used in wait guard even though it is
+             * not protected by lock. This works because count can
+             * only decrease at this point (all other puts are shut
+             * out by lock), and we (or some other waiting put) are
+             * signalled if it ever changes from capacity. Similarly
+             * for all other uses of count in other wait guards.
+             */
+            while (count.get() == capacity) {
+                notFull.await();
+            }
+            enqueue(node);
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary up to the specified wait time for space to become available.
+     *
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        if (e == null) throw new NullPointerException();
+        long nanos = unit.toNanos(timeout);
+        final int c;
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            while (count.get() == capacity) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(new Node<E>(e));
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to method {@link BlockingQueue#add add}, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        final AtomicInteger count = this.count;
+        if (count.get() == capacity)
+            return false;
+        final int c;
+        final Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            if (count.get() == capacity)
+                return false;
+            enqueue(node);
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return true;
+    }
+
+    public E take() throws InterruptedException {
+        final E x;
+        final int c;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        final E x;
+        final int c;
+        long nanos = unit.toNanos(timeout);
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll() {
+        final AtomicInteger count = this.count;
+        if (count.get() == 0)
+            return null;
+        final E x;
+        final int c;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            if (count.get() == 0)
+                return null;
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E peek() {
+        final AtomicInteger count = this.count;
+        if (count.get() == 0)
+            return null;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            return (count.get() > 0) ? head.next.item : null;
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Unlinks interior Node p with predecessor pred.
+     */
+    void unlink(Node<E> p, Node<E> pred) {
+        // assert putLock.isHeldByCurrentThread();
+        // assert takeLock.isHeldByCurrentThread();
+        // p.next is not changed, to allow iterators that are
+        // traversing p to maintain their weak-consistency guarantee.
+        p.item = null;
+        pred.next = p.next;
+        if (last == p)
+            last = pred;
+        if (count.getAndDecrement() == capacity)
+            notFull.signal();
+    }
+
+    /**
+     * 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) {
+        if (o == null) return false;
+        fullyLock();
+        try {
+            for (Node<E> pred = head, p = pred.next;
+                 p != null;
+                 pred = p, p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p, pred);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * 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;
+        fullyLock();
+        try {
+            for (Node<E> p = head.next; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        fullyLock();
+        try {
+            int size = count.get();
+            Object[] a = new Object[size];
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        fullyLock();
+        try {
+            int size = count.get();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), size);
+
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        fullyLock();
+        try {
+            for (Node<E> p, h = head; (p = h.next) != null; h = p) {
+                h.next = h;
+                p.item = null;
+            }
+            head = last;
+            // assert head.item == null && head.next == null;
+            if (count.getAndSet(0) == capacity)
+                notFull.signal();
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        boolean signalNotFull = false;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            int n = Math.min(maxElements, count.get());
+            // count.get provides visibility to first n Nodes
+            Node<E> h = head;
+            int i = 0;
+            try {
+                while (i < n) {
+                    Node<E> p = h.next;
+                    c.add(p.item);
+                    p.item = null;
+                    h.next = h;
+                    h = p;
+                    ++i;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    // assert h.item == null;
+                    head = h;
+                    signalNotFull = (count.getAndAdd(-i) == capacity);
+                }
+            }
+        } finally {
+            takeLock.unlock();
+            if (signalNotFull)
+                signalNotFull();
+        }
+    }
+
+    /**
+     * Used for any element traversal that is not entirely under lock.
+     * Such traversals must handle both:
+     * - dequeued nodes (p.next == p)
+     * - (possibly multiple) interior removed nodes (p.item == null)
+     */
+    Node<E> succ(Node<E> p) {
+        if (p == (p = p.next))
+            p = head.next;
+        return p;
+    }
+
+    /**
+     * 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 href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Weakly-consistent iterator.
+     *
+     * Lazily updated ancestor field provides expected O(1) remove(),
+     * but still O(n) in the worst case, whenever the saved ancestor
+     * is concurrently deleted.
+     */
+    private class Itr implements Iterator<E> {
+        private Node<E> next;           // Node holding nextItem
+        private E nextItem;             // next item to hand out
+        private Node<E> lastRet;
+        private Node<E> ancestor;       // Helps unlink lastRet on remove()
+
+        Itr() {
+            fullyLock();
+            try {
+                if ((next = head.next) != null)
+                    nextItem = next.item;
+            } finally {
+                fullyUnlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        public E next() {
+            Node<E> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            lastRet = p;
+            E x = nextItem;
+            fullyLock();
+            try {
+                E e = null;
+                for (p = p.next; p != null && (e = p.item) == null; )
+                    p = succ(p);
+                next = p;
+                nextItem = e;
+            } finally {
+                fullyUnlock();
+            }
+            return x;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            // A variant of forEachFrom
+            Objects.requireNonNull(action);
+            Node<E> p;
+            if ((p = next) == null) return;
+            lastRet = p;
+            next = null;
+            final int batchSize = 64;
+            Object[] es = null;
+            int n, len = 1;
+            do {
+                fullyLock();
+                try {
+                    if (es == null) {
+                        p = p.next;
+                        for (Node<E> q = p; q != null; q = succ(q))
+                            if (q.item != null && ++len == batchSize)
+                                break;
+                        es = new Object[len];
+                        es[0] = nextItem;
+                        nextItem = null;
+                        n = 1;
+                    } else
+                        n = 0;
+                    for (; p != null && n < len; p = succ(p))
+                        if ((es[n] = p.item) != null) {
+                            lastRet = p;
+                            n++;
+                        }
+                } finally {
+                    fullyUnlock();
+                }
+                for (int i = 0; i < n; i++) {
+                    @SuppressWarnings("unchecked") E e = (E) es[i];
+                    action.accept(e);
+                }
+            } while (n > 0 && p != null);
+        }
+
+        public void remove() {
+            Node<E> p = lastRet;
+            if (p == null)
+                throw new IllegalStateException();
+            lastRet = null;
+            fullyLock();
+            try {
+                if (p.item != null) {
+                    if (ancestor == null)
+                        ancestor = head;
+                    ancestor = findPred(p, ancestor);
+                    unlink(p, ancestor);
+                }
+            } finally {
+                fullyUnlock();
+            }
+        }
+    }
+
+    /**
+     * A customized variant of Spliterators.IteratorSpliterator.
+     * Keep this class in sync with (very similar) LBDSpliterator.
+     */
+    private final class LBQSpliterator implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est = size();  // size estimate
+
+        LBQSpliterator() {}
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            if (!exhausted &&
+                ((h = current) != null || (h = head.next) != null)
+                && h.next != null) {
+                int n = batch = Math.min(batch + 1, MAX_BATCH);
+                Object[] a = new Object[n];
+                int i = 0;
+                Node<E> p = current;
+                fullyLock();
+                try {
+                    if (p != null || (p = head.next) != null)
+                        for (; p != null && i < n; p = succ(p))
+                            if ((a[i] = p.item) != null)
+                                i++;
+                } finally {
+                    fullyUnlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0)
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+            }
+            return null;
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                E e = null;
+                fullyLock();
+                try {
+                    Node<E> p;
+                    if ((p = current) != null || (p = head.next) != null)
+                        do {
+                            e = p.item;
+                            p = succ(p);
+                        } while (e == null && p != null);
+                    if ((current = p) == null)
+                        exhausted = true;
+                } finally {
+                    fullyUnlock();
+                }
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                current = null;
+                forEachFrom(action, p);
+            }
+        }
+
+        public int characteristics() {
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBQSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, null);
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, traversal starts at head.
+     */
+    void forEachFrom(Consumer<? super E> action, Node<E> p) {
+        // Extract batches of elements while holding the lock; then
+        // run the action on the elements while not
+        final int batchSize = 64;       // max number of elements per batch
+        Object[] es = null;             // container for batch of elements
+        int n, len = 0;
+        do {
+            fullyLock();
+            try {
+                if (es == null) {
+                    if (p == null) p = head.next;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == batchSize)
+                            break;
+                    es = new Object[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    if ((es[n] = p.item) != null)
+                        n++;
+            } finally {
+                fullyUnlock();
+            }
+            for (int i = 0; i < n; i++) {
+                @SuppressWarnings("unchecked") E e = (E) es[i];
+                action.accept(e);
+            }
+        } while (n > 0 && p != null);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /**
+     * Returns the predecessor of live node p, given a node that was
+     * once a live ancestor of p (or head); allows unlinking of p.
+     */
+    Node<E> findPred(Node<E> p, Node<E> ancestor) {
+        // assert p.item != null;
+        if (ancestor.item == null)
+            ancestor = head;
+        // Fails with NPE if precondition not satisfied
+        for (Node<E> q; (q = ancestor.next) != p; )
+            ancestor = q;
+        return ancestor;
+    }
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        Node<E> p = null, ancestor = head;
+        Node<E>[] nodes = null;
+        int n, len = 0;
+        do {
+            // 1. Extract batch of up to 64 elements while holding the lock.
+            fullyLock();
+            try {
+                if (nodes == null) {  // first batch; initialize
+                    p = head.next;
+                    for (Node<E> q = p; q != null; q = succ(q))
+                        if (q.item != null && ++len == 64)
+                            break;
+                    nodes = (Node<E>[]) new Node<?>[len];
+                }
+                for (n = 0; p != null && n < len; p = succ(p))
+                    nodes[n++] = p;
+            } finally {
+                fullyUnlock();
+            }
+
+            // 2. Run the filter on the elements while lock is free.
+            long deathRow = 0L;       // "bitset" of size 64
+            for (int i = 0; i < n; i++) {
+                final E e;
+                if ((e = nodes[i].item) != null && filter.test(e))
+                    deathRow |= 1L << i;
+            }
+
+            // 3. Remove any filtered elements while holding the lock.
+            if (deathRow != 0) {
+                fullyLock();
+                try {
+                    for (int i = 0; i < n; i++) {
+                        final Node<E> q;
+                        if ((deathRow & (1L << i)) != 0L
+                            && (q = nodes[i]).item != null) {
+                            ancestor = findPred(q, ancestor);
+                            unlink(q, ancestor);
+                            removed = true;
+                        }
+                        nodes[i] = null; // help GC
+                    }
+                } finally {
+                    fullyUnlock();
+                }
+            }
+        } while (n > 0 && p != null);
+        return removed;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity is emitted (int), followed by all of
+     * its elements (each an {@code Object}) in the proper order,
+     * followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        fullyLock();
+        try {
+            // Write out any hidden stuff, plus capacity
+            s.defaultWriteObject();
+
+            // Write out all elements in the proper order.
+            for (Node<E> p = head.next; p != null; p = p.next)
+                s.writeObject(p.item);
+
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in capacity, and any hidden stuff
+        s.defaultReadObject();
+
+        count.set(0);
+        last = head = new Node<E>(null);
+
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/LinkedTransferQueue.java b/android-35/java/util/concurrent/LinkedTransferQueue.java
new file mode 100644
index 0000000..cc30c5d
--- /dev/null
+++ b/android-35/java/util/concurrent/LinkedTransferQueue.java
@@ -0,0 +1,1666 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * 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.
+ *
+ * <p>Bulk operations that add, remove, or examine multiple elements,
+ * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
+ * are <em>not</em> guaranteed to be performed atomically.
+ * For example, a {@code forEach} traversal concurrent with an {@code
+ * addAll} operation might observe 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.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+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.rochester.edu/~scott/papers/2004_DISC_dual_DS.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/~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.  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 chains of dead nodes.
+     * (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).
+     *
+     * 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 two phases. The first is implemented
+     * in method xfer, the second in method awaitMatch.
+     *
+     * 1. Traverse until matching or appending (method xfer)
+     *
+     *    Conceptually, we simply traverse all nodes starting from head.
+     *    If we encounter an unmatched node of opposite mode, we match
+     *    it and return, also updating head (by at least 2 hops) to
+     *    one past the matched node (or the node itself if it's the
+     *    pinned trailing node).  Traversals also check for the
+     *    possibility of falling off-list, in which case they restart.
+     *
+     *    If the trailing node of the list is reached, a match is not
+     *    possible.  If this call was untimed poll or tryTransfer
+     *    (argument "how" is NOW), return empty-handed immediately.
+     *    Else a new node is CAS-appended.  On successful append, if
+     *    this call was ASYNC (e.g. offer), an element was
+     *    successfully added to the end of the queue and we return.
+     *
+     *    Of course, this naive traversal is O(n) when no match is
+     *    possible.  We optimize the traversal by maintaining a tail
+     *    pointer, which is expected to be "near" the end of the list.
+     *    It is only safe to fast-forward to tail (in the presence of
+     *    arbitrary concurrent changes) if it is pointing to a node of
+     *    the same mode, even if it is dead (in this case no preceding
+     *    node could still be matchable by this traversal).  If we
+     *    need to restart due to falling off-list, we can again
+     *    fast-forward to tail, but only if it has changed since the
+     *    last traversal (else we might loop forever).  If tail cannot
+     *    be used, traversal starts at head (but in this case we
+     *    expect to be able to match near head).  As with head, we
+     *    CAS-advance the tail pointer by at least two hops.
+     *
+     * 2. 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. To
+     *    improve performance in common single-source / single-sink
+     *    usages when there are more tasks that cores, an initial
+     *    Thread.yield is tried when there is apparently only one
+     *    waiter.  In other cases, waiters may help with some
+     *    bookkeeping, then park/unpark.
+     *
+     * ** 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 at the trailing node but otherwise
+     * never 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 the need to sweep the
+     * next time any thread would otherwise block in awaitMatch. Also,
+     * because traversal operations on the linked list of nodes are a
+     * natural opportunity to sweep dead nodes, we generally do so,
+     * including all the operations that might remove elements as they
+     * traverse, such as removeIf and Iterator.remove.  This largely
+     * eliminates long chains of dead interior nodes, except from
+     * cancelled or timed out blocking operations.
+     *
+     * 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.
+     */
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices.
+     * Using a power of two minus one simplifies some comparisons.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1023L;
+
+    /**
+     * 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.  Writes that are intrinsically ordered wrt
+     * other accesses or CASes use simple relaxed forms.
+     */
+    static final class Node implements ForkJoinPool.ManagedBlocker {
+        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 when not waiting for a match
+
+        /**
+         * Constructs a data node holding item if item is non-null,
+         * else a request node.  Uses relaxed write because item can
+         * only be seen after piggy-backing publication via CAS.
+         */
+        Node(Object item) {
+            ITEM.set(this, item);
+            isData = (item != null);
+        }
+
+        /** Constructs a (matched data) dummy node. */
+        Node() {
+            isData = true;
+        }
+
+        final boolean casNext(Node cmp, Node val) {
+            // assert val != null;
+            return NEXT.compareAndSet(this, cmp, val);
+        }
+
+        final boolean casItem(Object cmp, Object val) {
+            // assert isData == (cmp != null);
+            // assert isData == (val == null);
+            // assert !(cmp instanceof Node);
+            return ITEM.compareAndSet(this, cmp, val);
+        }
+
+        /**
+         * Links node to itself to avoid garbage retention.  Called
+         * only after CASing head field, so uses relaxed write.
+         */
+        final void selfLink() {
+            // assert isMatched();
+            NEXT.setRelease(this, this);
+        }
+
+        final void appendRelaxed(Node next) {
+            // assert next != null;
+            // assert this.next == null;
+            NEXT.setOpaque(this, next);
+        }
+
+        /**
+         * Returns true if this node has been matched, including the
+         * case of artificial matches due to cancellation.
+         */
+        final boolean isMatched() {
+            return isData == (item == null);
+        }
+
+        /** Tries to CAS-match this node; if successful, wakes waiter. */
+        final boolean tryMatch(Object cmp, Object val) {
+            if (casItem(cmp, val)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * 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;
+            return d != haveData && d != (item == null);
+        }
+
+        public final boolean isReleasable() {
+            return (isData == (item == null)) ||
+                Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park();
+            return true;
+        }
+
+        private static final long serialVersionUID = -3375979862319811754L;
+    }
+
+    /**
+     * A node from which the first live (non-matched) node (if any)
+     * can be reached in O(1) time.
+     * Invariants:
+     * - all live nodes are reachable from head via .next
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * Non-invariants:
+     * - head may or may not be live
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     */
+    transient volatile Node head;
+
+    /**
+     * A node from which the last node on list (that is, the unique
+     * node with node.next == null) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always reachable from tail via .next
+     * - tail != null
+     * Non-invariants:
+     * - tail may or may not be live
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     * - tail.next may or may not be self-linked.
+     */
+    private transient volatile Node tail;
+
+    /** The number of apparent failures to unsplice cancelled nodes */
+    private transient volatile boolean needSweep;
+
+    private boolean casTail(Node cmp, Node val) {
+        // assert cmp != null;
+        // assert val != null;
+        return TAIL.compareAndSet(this, cmp, val);
+    }
+
+    private boolean casHead(Node cmp, Node val) {
+        return HEAD.compareAndSet(this, cmp, val);
+    }
+
+    /**
+     * Tries to CAS pred.next (or head, if pred is null) from c to p.
+     * Caller must ensure that we're not unlinking the trailing node.
+     */
+    private boolean tryCasSuccessor(Node pred, Node c, Node p) {
+        // assert p != null;
+        // assert c.isData != (c.item != null);
+        // assert c != p;
+        if (pred != null)
+            return pred.casNext(c, p);
+        if (casHead(c, p)) {
+            c.selfLink();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Collapses dead (matched) nodes between pred and q.
+     * @param pred the last known live node, or null if none
+     * @param c the first dead node
+     * @param p the last dead node
+     * @param q p.next: the next live node, or null if at end
+     * @return pred if pred still alive and CAS succeeded; else p
+     */
+    private Node skipDeadNodes(Node pred, Node c, Node p, Node q) {
+        // assert pred != c;
+        // assert p != q;
+        // assert c.isMatched();
+        // assert p.isMatched();
+        if (q == null) {
+            // Never unlink trailing node.
+            if (c == p) return pred;
+            q = p;
+        }
+        return (tryCasSuccessor(pred, c, q)
+                && (pred == null || !pred.isMatched()))
+            ? pred : p;
+    }
+
+    /**
+     * Collapses dead (matched) nodes from h (which was once head) to p.
+     * Caller ensures all nodes from h up to and including p are dead.
+     */
+    private void skipDeadNodesNearHead(Node h, Node p) {
+        // assert h != null;
+        // assert h != p;
+        // assert p.isMatched();
+        for (;;) {
+            final Node q;
+            if ((q = p.next) == null) break;
+            else if (!q.isMatched()) { p = q; break; }
+            else if (p == (p = q)) return;
+        }
+        if (casHead(h, p))
+            h.selfLink();
+    }
+
+    /* 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
+
+    /**
+     * 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
+     */
+    @SuppressWarnings("unchecked")
+    private E xfer(E e, boolean haveData, int how, long nanos) {
+        if (haveData && (e == null))
+            throw new NullPointerException();
+
+        restart: for (Node s = null, t = null, h = null;;) {
+            for (Node p = (t != (t = tail) && t.isData == haveData) ? t
+                     : (h = head);; ) {
+                final Node q; final Object item;
+                if (p.isData != haveData
+                    && haveData == ((item = p.item) == null)) {
+                    if (h == null) h = head;
+                    if (p.tryMatch(item, e)) {
+                        if (h != p) skipDeadNodesNearHead(h, p);
+                        return (E) item;
+                    }
+                }
+                if ((q = p.next) == null) {
+                    if (how == NOW) return e;
+                    if (s == null) s = new Node(e);
+                    if (!p.casNext(null, s)) continue;
+                    if (p != t) casTail(t, s);
+                    if (how == ASYNC) return e;
+                    return awaitMatch(s, p, e, (how == TIMED), nanos);
+                }
+                if (p == (p = q)) continue restart;
+            }
+        }
+    }
+
+    /**
+     * Possibly blocks until node s is matched or caller gives up.
+     *
+     * @param s the waiting node
+     * @param pred the predecessor of s, 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
+     */
+    @SuppressWarnings("unchecked")
+    private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
+        final boolean isData = s.isData;
+        final long deadline = timed ? System.nanoTime() + nanos : 0L;
+        final Thread w = Thread.currentThread();
+        int stat = -1;                   // -1: may yield, +1: park, else 0
+        Object item;
+        while ((item = s.item) == e) {
+            if (needSweep)               // help clean
+                sweep();
+            else if ((timed && nanos <= 0L) || w.isInterrupted()) {
+                if (s.casItem(e, (e == null) ? s : null)) {
+                    unsplice(pred, s);   // cancelled
+                    return e;
+                }
+            }
+            else if (stat <= 0) {
+                if (pred != null && pred.next == s) {
+                    if (stat < 0 &&
+                        (pred.isData != isData || pred.isMatched())) {
+                        stat = 0;        // yield once if first
+                        Thread.yield();
+                    }
+                    else {
+                        stat = 1;
+                        s.waiter = w;    // enable unpark
+                    }
+                }                        // else signal in progress
+            }
+            else if ((item = s.item) != e)
+                break;                   // recheck
+            else if (!timed) {
+                LockSupport.setCurrentBlocker(this);
+                try {
+                    ForkJoinPool.managedBlock(s);
+                } catch (InterruptedException cannotHappen) { }
+                LockSupport.setCurrentBlocker(null);
+            }
+            else {
+                nanos = deadline - System.nanoTime();
+                if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanos);
+            }
+        }
+        if (stat == 1)
+            WAITER.set(s, null);
+        if (!isData)
+            ITEM.set(s, s);              // self-link to avoid garbage
+        return (E) item;
+    }
+
+    /* -------------- Traversal methods -------------- */
+
+    /**
+     * Returns the first unmatched data node, or null if none.
+     * Callers must recheck if the returned node is unmatched
+     * before using.
+     */
+    final Node firstDataNode() {
+        Node first = null;
+        restartFromHead: for (;;) {
+            Node h = head, p = h;
+            while (p != null) {
+                if (p.item != null) {
+                    if (p.isData) {
+                        first = p;
+                        break;
+                    }
+                }
+                else if (!p.isData)
+                    break;
+                final Node q;
+                if ((q = p.next) == null)
+                    break;
+                if (p == (p = q))
+                    continue restartFromHead;
+            }
+            if (p != h && casHead(h, p))
+                h.selfLink();
+            return first;
+        }
+    }
+
+    /**
+     * Traverses and counts unmatched nodes of the given mode.
+     * Used by methods size and getWaitingConsumerCount.
+     */
+    private int countOfMode(boolean data) {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node p = head; p != null;) {
+                if (!p.isMatched()) {
+                    if (p.isData != data)
+                        return 0;
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null) {
+                        if (a == null)
+                            a = new String[4];
+                        else if (size == a.length)
+                            a = Arrays.copyOf(a, 2 * size);
+                        String s = item.toString();
+                        a[size++] = s;
+                        charLength += s.length();
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null) {
+                        if (x == null)
+                            x = new Object[4];
+                        else if (size == x.length)
+                            x = Arrays.copyOf(x, 2 * (size + 4));
+                        x[size++] = item;
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        Objects.requireNonNull(a);
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Weakly-consistent iterator.
+     *
+     * Lazily updated ancestor is expected to be amortized O(1) remove(),
+     * but O(n) in the worst case, when lastRet is concurrently deleted.
+     */
+    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 ancestor;   // Helps unlink lastRet on remove()
+
+        /**
+         * Moves to next node after pred, or first node if pred null.
+         */
+        @SuppressWarnings("unchecked")
+        private void advance(Node pred) {
+            for (Node p = (pred == null) ? head : pred.next, c = p;
+                 p != null; ) {
+                final Object item;
+                if ((item = p.item) != null && p.isData) {
+                    nextNode = p;
+                    nextItem = (E) item;
+                    if (c != p)
+                        tryCasSuccessor(pred, c, p);
+                    return;
+                }
+                else if (!p.isData && item == null)
+                    break;
+                if (c != p && !tryCasSuccessor(pred, c, c = p)) {
+                    pred = p;
+                    c = p = p.next;
+                }
+                else if (p == (p = p.next)) {
+                    pred = null;
+                    c = p = head;
+                }
+            }
+            nextItem = null;
+            nextNode = null;
+        }
+
+        Itr() {
+            advance(null);
+        }
+
+        public final boolean hasNext() {
+            return nextNode != null;
+        }
+
+        public final E next() {
+            final Node p;
+            if ((p = nextNode) == null) throw new NoSuchElementException();
+            E e = nextItem;
+            advance(lastRet = p);
+            return e;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node q = null;
+            for (Node p; (p = nextNode) != null; advance(q = p))
+                action.accept(nextItem);
+            if (q != null)
+                lastRet = q;
+        }
+
+        public final void remove() {
+            final Node lastRet = this.lastRet;
+            if (lastRet == null)
+                throw new IllegalStateException();
+            this.lastRet = null;
+            if (lastRet.item == null)   // already deleted?
+                return;
+            // Advance ancestor, collapsing intervening dead nodes
+            Node pred = ancestor;
+            for (Node p = (pred == null) ? head : pred.next, c = p, q;
+                 p != null; ) {
+                if (p == lastRet) {
+                    final Object item;
+                    if ((item = p.item) != null)
+                        p.tryMatch(item, null);
+                    if ((q = p.next) == null) q = p;
+                    if (c != q) tryCasSuccessor(pred, c, q);
+                    ancestor = pred;
+                    return;
+                }
+                final Object item; final boolean pAlive;
+                if (pAlive = ((item = p.item) != null && p.isData)) {
+                    // exceptionally, nothing to do
+                }
+                else if (!p.isData && item == null)
+                    break;
+                if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) {
+                    pred = p;
+                    c = p = p.next;
+                }
+                else if (p == (p = p.next)) {
+                    pred = null;
+                    c = p = head;
+                }
+            }
+            // traversal failed to find lastRet; must have been deleted;
+            // leave ancestor at original location to avoid overshoot;
+            // better luck next time!
+
+            // assert lastRet.isMatched();
+        }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    final class LTQSpliterator implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node current;       // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        LTQSpliterator() {}
+
+        public Spliterator<E> trySplit() {
+            Node p, q;
+            if ((p = current()) == null || (q = p.next) == null)
+                return null;
+            int i = 0, n = batch = Math.min(batch + 1, MAX_BATCH);
+            Object[] a = null;
+            do {
+                final Object item = p.item;
+                if (p.isData) {
+                    if (item != null) {
+                        if (a == null)
+                            a = new Object[n];
+                        a[i++] = item;
+                    }
+                } else if (item == null) {
+                    p = null;
+                    break;
+                }
+                if (p == (p = q))
+                    p = firstDataNode();
+            } while (p != null && (q = p.next) != null && i < n);
+            setCurrent(p);
+            return (i == 0) ? null :
+                Spliterators.spliterator(a, 0, i, (Spliterator.ORDERED |
+                                                   Spliterator.NONNULL |
+                                                   Spliterator.CONCURRENT));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Node p;
+            if ((p = current()) != null) {
+                current = null;
+                exhausted = true;
+                forEachFrom(action, p);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Node p;
+            if ((p = current()) != null) {
+                E e = null;
+                do {
+                    final Object item = p.item;
+                    final boolean isData = p.isData;
+                    if (p == (p = p.next))
+                        p = head;
+                    if (isData) {
+                        if (item != null) {
+                            e = (E) item;
+                            break;
+                        }
+                    }
+                    else if (item == null)
+                        p = null;
+                } while (p != null);
+                setCurrent(p);
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private void setCurrent(Node p) {
+            if ((current = p) == null)
+                exhausted = true;
+        }
+
+        private Node current() {
+            Node p;
+            if ((p = current) == null && !exhausted)
+                setCurrent(p = firstDataNode());
+            return p;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LTQSpliterator();
+    }
+
+    /* -------------- 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
+     * @param s the node to be unspliced
+     */
+    final void unsplice(Node pred, Node s) {
+        // assert pred != null;
+        // assert pred != s;
+        // assert s != null;
+        // assert s.isMatched();
+        // assert (SWEEP_THRESHOLD & (SWEEP_THRESHOLD - 1)) == 0;
+        s.waiter = null; // disable signals
+        /*
+         * 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, set needSweep;
+         */
+        if (pred != null && 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)
+                        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.selfLink();  // advance head
+                }
+                if (pred.next != pred && s.next != s)
+                    needSweep = true;
+            }
+        }
+    }
+
+    /**
+     * Unlinks matched (typically cancelled) nodes encountered in a
+     * traversal from head.
+     */
+    private void sweep() {
+        needSweep = false;
+        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);
+        }
+    }
+
+    /**
+     * Creates an initially empty {@code LinkedTransferQueue}.
+     */
+    public LinkedTransferQueue() {
+        head = tail = new Node();
+    }
+
+    /**
+     * 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) {
+        Node h = null, t = null;
+        for (E e : c) {
+            Node newNode = new Node(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node();
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * 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, 0L);
+    }
+
+    /**
+     * 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 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, 0L);
+        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, 0L);
+        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, 0L);
+        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, 0L) == 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, 0L) != 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, 0L);
+        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, 0L);
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null; n++)
+            c.add(e);
+        return n;
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null; n++)
+            c.add(e);
+        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 href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    public E peek() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null) {
+                        @SuppressWarnings("unchecked") E e = (E) item;
+                        return e;
+                    }
+                }
+                else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return firstDataNode() == null;
+    }
+
+    public boolean hasWaitingConsumer() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null)
+                        break;
+                }
+                else if (item == null)
+                    return true;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 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) {
+        if (o == null) return false;
+        restartFromHead: for (;;) {
+            for (Node p = head, pred = null; p != null; ) {
+                Node q = p.next;
+                final Object item;
+                if ((item = p.item) != null) {
+                    if (p.isData) {
+                        if (o.equals(item) && p.tryMatch(item, null)) {
+                            skipDeadNodes(pred, p, p, q);
+                            return true;
+                        }
+                        pred = p; p = q; continue;
+                    }
+                }
+                else if (!p.isData)
+                    break;
+                for (Node c = p;; q = p.next) {
+                    if (q == null || !q.isMatched()) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 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;
+        restartFromHead: for (;;) {
+            for (Node p = head, pred = null; p != null; ) {
+                Node q = p.next;
+                final Object item;
+                if ((item = p.item) != null) {
+                    if (p.isData) {
+                        if (o.equals(item))
+                            return true;
+                        pred = p; p = q; continue;
+                    }
+                }
+                else if (!p.isData)
+                    break;
+                for (Node c = p;; q = p.next) {
+                    if (q == null || !q.isMatched()) {
+                        pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                    }
+                    if (p == (p = q)) continue restartFromHead;
+                }
+            }
+            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 BlockingQueue#remainingCapacity()})
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    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 this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in elements until trailing null sentinel found
+        Node h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            Node newNode = new Node(item);
+            if (h == null)
+                h = t = newNode;
+            else
+                t.appendRelaxed(t = newNode);
+        }
+        if (h == null)
+            h = t = new Node();
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    public void clear() {
+        bulkRemove(e -> true);
+    }
+
+    /**
+     * Tolerate this many consecutive dead nodes before CAS-collapsing.
+     * Amortized cost of clear() is (1 + 1/MAX_HOPS) CASes per element.
+     */
+    private static final int MAX_HOPS = 8;
+
+    /** Implementation of bulk remove methods. */
+    @SuppressWarnings("unchecked")
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        boolean removed = false;
+        restartFromHead: for (;;) {
+            int hops = MAX_HOPS;
+            // c will be CASed to collapse intervening dead nodes between
+            // pred (or head if null) and p.
+            for (Node p = head, c = p, pred = null, q; p != null; p = q) {
+                q = p.next;
+                final Object item; boolean pAlive;
+                if (pAlive = ((item = p.item) != null && p.isData)) {
+                    if (filter.test((E) item)) {
+                        if (p.tryMatch(item, null))
+                            removed = true;
+                        pAlive = false;
+                    }
+                }
+                else if (!p.isData && item == null)
+                    break;
+                if (pAlive || q == null || --hops == 0) {
+                    // p might already be self-linked here, but if so:
+                    // - CASing head will surely fail
+                    // - CASing pred's next will be useless but harmless.
+                    if ((c != p && !tryCasSuccessor(pred, c, c = p))
+                        || pAlive) {
+                        // if CAS failed or alive, abandon old pred
+                        hops = MAX_HOPS;
+                        pred = p;
+                        c = q;
+                    }
+                } else if (p == q)
+                    continue restartFromHead;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Runs action on each element found during a traversal starting at p.
+     * If p is null, the action is not run.
+     */
+    @SuppressWarnings("unchecked")
+    void forEachFrom(Consumer<? super E> action, Node p) {
+        for (Node pred = null; p != null; ) {
+            Node q = p.next;
+            final Object item;
+            if ((item = p.item) != null) {
+                if (p.isData) {
+                    action.accept((E) item);
+                    pred = p; p = q; continue;
+                }
+            }
+            else if (!p.isData)
+                break;
+            for (Node c = p;; q = p.next) {
+                if (q == null || !q.isMatched()) {
+                    pred = skipDeadNodes(pred, c, p, q); p = q; break;
+                }
+                if (p == (p = q)) { pred = null; p = head; break; }
+            }
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        forEachFrom(action, head);
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle HEAD;
+    private static final VarHandle TAIL;
+    static final VarHandle ITEM;
+    static final VarHandle NEXT;
+    static final VarHandle WAITER;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
+                                   Node.class);
+            TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
+                                   Node.class);
+            ITEM = l.findVarHandle(Node.class, "item", Object.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/Phaser.java b/android-35/java/util/concurrent/Phaser.java
new file mode 100644
index 0000000..4d4df40
--- /dev/null
+++ b/android-35/java/util/concurrent/Phaser.java
@@ -0,0 +1,1154 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A reusable synchronization barrier, similar in functionality to
+ * {@link CyclicBarrier} and {@link 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}.
+ *       Progress is ensured if the pool's parallelism level can
+ *       accommodate the maximum number of simultaneously blocked
+ *       parties.
+ *
+ * </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>Memory consistency effects: Actions prior to any form of arrive
+ * method <a href="package-summary.html#MemoryVisibility">
+ * <i>happen-before</i></a> a corresponding phase advance and
+ * onAdvance actions (if present), which in turn <i>happen-before</i>
+ * actions following the phase advance.
+ *
+ * <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 all the actions, then deregister, as in:
+ *
+ * <pre> {@code
+ * void runTasks(List<Runnable> tasks) {
+ *   Phaser startingGate = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (Runnable task : tasks) {
+ *     startingGate.register();
+ *     new Thread(() -> {
+ *       startingGate.arriveAndAwaitAdvance();
+ *       task.run();
+ *     }).start();
+ *   }
+ *
+ *   // deregister self to allow threads to proceed
+ *   startingGate.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, int iterations) {
+ *   Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations - 1 || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread(() -> {
+ *       do {
+ *         task.run();
+ *         phaser.arriveAndAwaitAdvance();
+ *       } while (!phaser.isTerminated());
+ *     }).start();
+ *   }
+ *   // allow threads to proceed; don't wait for them
+ *   phaser.arriveAndDeregister();
+ * }}</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
+ * @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;
+
+    /**
+     * 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 (STATE.compareAndSet(this, 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;
+                        STATE.compareAndSet(this, s, n);
+                        releaseWaiters(phase);
+                    }
+                    else if (nextUnarrived == 0) { // propagate deregistration
+                        phase = parent.doArrive(ONE_DEREGISTER);
+                        STATE.compareAndSet(this, 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 (STATE.compareAndSet(this, s, s + adjust))
+                        break;
+                }
+            }
+            else if (parent == null) {              // 1st root registration
+                long next = ((long)phase << PHASE_SHIFT) | adjust;
+                if (STATE.compareAndSet(this, 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 (!STATE.weakCompareAndSet
+                               (this, 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) &&
+                   !STATE.weakCompareAndSet
+                   (this, 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 (STATE.compareAndSet(this, 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 (!STATE.compareAndSet(this, 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 (STATE.compareAndSet(root, 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;
+                }
+                // Android-removed: remove usage of Thread.onSpinWait. http://b/202837191
+                // else
+                //     Thread.onSpinWait();
+            }
+            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 cantHappen) {
+                    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;
+        final long deadline;
+        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.deadline = timed ? System.nanoTime() + nanos : 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 &&
+                (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
+                thread = null;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean block() {
+            while (!isReleasable()) {
+                if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            return true;
+        }
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle STATE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            STATE = l.findVarHandle(Phaser.class, "state", long.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/PriorityBlockingQueue.java b/android-35/java/util/concurrent/PriorityBlockingQueue.java
new file mode 100644
index 0000000..911c8ce
--- /dev/null
+++ b/android-35/java/util/concurrent/PriorityBlockingQueue.java
@@ -0,0 +1,1110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.SortedSet;
+import java.util.Spliterator;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} that uses
+ * the same ordering rules as class {@link PriorityQueue} and supplies
+ * blocking retrieval operations.  While this queue is logically
+ * unbounded, attempted additions may fail due to resource exhaustion
+ * (causing {@code OutOfMemoryError}). This class does not permit
+ * {@code null} elements.  A priority queue relying on {@linkplain
+ * Comparable natural ordering} also does not permit insertion of
+ * non-comparable objects (doing so results in
+ * {@code ClassCastException}).
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ * The Iterator provided in method {@link #iterator()} and the
+ * Spliterator provided in method {@link #spliterator()} are <em>not</em>
+ * guaranteed to traverse the elements of the PriorityBlockingQueue in
+ * any particular order. If you need ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo} can
+ * be used to <em>remove</em> some or all elements in priority order and
+ * place them in another collection.
+ *
+ * <p>Operations on this class make no guarantees about the ordering
+ * of elements with equal priority. If you need to enforce an
+ * ordering, you can define custom classes or comparators that use a
+ * secondary key to break ties in primary priority values.  For
+ * example, here is a class that applies first-in-first-out
+ * tie-breaking to comparable elements. To use it, you would insert a
+ * {@code new FIFOEntry(anEntry)} instead of a plain entry object.
+ *
+ * <pre> {@code
+ * class FIFOEntry<E extends Comparable<? super E>>
+ *     implements Comparable<FIFOEntry<E>> {
+ *   static final AtomicLong seq = new AtomicLong();
+ *   final long seqNum;
+ *   final E entry;
+ *   public FIFOEntry(E entry) {
+ *     seqNum = seq.getAndIncrement();
+ *     this.entry = entry;
+ *   }
+ *   public E getEntry() { return entry; }
+ *   public int compareTo(FIFOEntry<E> other) {
+ *     int res = entry.compareTo(other.entry);
+ *     if (res == 0 && other.entry != this.entry)
+ *       res = (seqNum < other.seqNum ? -1 : 1);
+ *     return res;
+ *   }
+ * }}</pre>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+@SuppressWarnings("unchecked")
+public class PriorityBlockingQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 5595510919245408276L;
+
+    /*
+     * The implementation uses an array-based binary heap, with public
+     * operations protected with a single lock. However, allocation
+     * during resizing uses a simple spinlock (used only while not
+     * holding main lock) in order to allow takes to operate
+     * concurrently with allocation.  This avoids repeated
+     * postponement of waiting consumers and consequent element
+     * build-up. The need to back away from lock during allocation
+     * makes it impossible to simply wrap delegated
+     * 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 expense of
+     * transiently doubling overhead.
+     */
+
+    /**
+     * Default array capacity.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    private transient Object[] queue;
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    private transient int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    private transient Comparator<? super E> comparator;
+
+    /**
+     * Lock used for all public operations.
+     */
+    private final ReentrantLock lock = new ReentrantLock();
+
+    /**
+     * Condition for blocking when empty.
+     */
+    @SuppressWarnings("serial") // Classes implementing Condition may be serializable.
+    private final Condition notEmpty = lock.newCondition();
+
+    /**
+     * Spinlock for allocation, acquired via CAS.
+     */
+    private transient volatile int allocationSpinLock;
+
+    /**
+     * A plain PriorityQueue used only for serialization,
+     * to maintain compatibility with previous versions
+     * of this class. Non-null only during serialization/deserialization.
+     */
+    private PriorityQueue<E> q;
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the default
+     * initial capacity (11) that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public PriorityBlockingQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified
+     * initial capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified initial
+     * capacity that orders its elements according to the specified
+     * comparator.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity,
+                                 Comparator<? super E> comparator) {
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.comparator = comparator;
+        this.queue = new Object[Math.max(1, initialCapacity)];
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} containing the elements
+     * in the specified collection.  If the specified collection is a
+     * {@link SortedSet} or a {@link PriorityBlockingQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public PriorityBlockingQueue(Collection<? extends E> c) {
+        boolean heapify = true; // true if not known to be in heap order
+        boolean screen = true;  // true if must screen for nulls
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            heapify = false;
+        }
+        else if (c instanceof PriorityBlockingQueue<?>) {
+            PriorityBlockingQueue<? extends E> pq =
+                (PriorityBlockingQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            screen = false;
+            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
+                heapify = false;
+        }
+        Object[] es = c.toArray();
+        int n = es.length;
+        // Android-changed: Defend against c.toArray (incorrectly) not returning Object[]
+        //                  (see b/204397945)
+        // if (c.getClass() != java.util.ArrayList.class)
+        if (es.getClass() != Object[].class)
+            es = Arrays.copyOf(es, n, Object[].class);
+        if (screen && (n == 1 || this.comparator != null)) {
+            for (Object e : es)
+                if (e == null)
+                    throw new NullPointerException();
+        }
+        this.queue = ensureNonEmpty(es);
+        this.size = n;
+        if (heapify)
+            heapify();
+    }
+
+    /** Ensures that queue[0] exists, helping peek() and poll(). */
+    private static Object[] ensureNonEmpty(Object[] es) {
+        return (es.length > 0) ? es : new Object[1];
+    }
+
+    /**
+     * Tries to grow array to accommodate at least one more element
+     * (but normally expand by about 50%), giving up (allowing retry)
+     * on contention (which we expect to be rare). Call only while
+     * holding lock.
+     *
+     * @param array the heap array
+     * @param oldCap the length of the array
+     */
+    private void tryGrow(Object[] array, int oldCap) {
+        lock.unlock(); // must release and then re-acquire main lock
+        Object[] newArray = null;
+        if (allocationSpinLock == 0 &&
+            ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
+            try {
+                int growth = (oldCap < 64)
+                    ? (oldCap + 2) // grow faster if small
+                    : (oldCap >> 1);
+                int newCap = ArraysSupport.newLength(oldCap, 1, growth);
+                if (queue == array)
+                    newArray = new Object[newCap];
+            } finally {
+                allocationSpinLock = 0;
+            }
+        }
+        if (newArray == null) // back off if another thread is allocating
+            Thread.yield();
+        lock.lock();
+        if (newArray != null && queue == array) {
+            queue = newArray;
+            System.arraycopy(array, 0, newArray, 0, oldCap);
+        }
+    }
+
+    /**
+     * Mechanics for poll().  Call only while holding lock.
+     */
+    private E dequeue() {
+        // assert lock.isHeldByCurrentThread();
+        final Object[] es;
+        final E result;
+
+        if ((result = (E) ((es = queue)[0])) != null) {
+            final int n;
+            final E x = (E) es[(n = --size)];
+            es[n] = null;
+            if (n > 0) {
+                final Comparator<? super E> cmp;
+                if ((cmp = comparator) == null)
+                    siftDownComparable(0, x, es, n);
+                else
+                    siftDownUsingComparator(0, x, es, n, cmp);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons, the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param es the heap array
+     */
+    private static <T> void siftUpComparable(int k, T x, Object[] es) {
+        Comparable<? super T> key = (Comparable<? super T>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = es[parent];
+            if (key.compareTo((T) e) >= 0)
+                break;
+            es[k] = e;
+            k = parent;
+        }
+        es[k] = key;
+    }
+
+    private static <T> void siftUpUsingComparator(
+        int k, T x, Object[] es, Comparator<? super T> cmp) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = es[parent];
+            if (cmp.compare(x, (T) e) >= 0)
+                break;
+            es[k] = e;
+            k = parent;
+        }
+        es[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param es the heap array
+     * @param n heap size
+     */
+    private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
+        // assert n > 0;
+        Comparable<? super T> key = (Comparable<? super T>)x;
+        int half = n >>> 1;           // loop while a non-leaf
+        while (k < half) {
+            int child = (k << 1) + 1; // assume left child is least
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n &&
+                ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
+                c = es[child = right];
+            if (key.compareTo((T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
+        }
+        es[k] = key;
+    }
+
+    private static <T> void siftDownUsingComparator(
+        int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
+        // assert n > 0;
+        int half = n >>> 1;
+        while (k < half) {
+            int child = (k << 1) + 1;
+            Object c = es[child];
+            int right = child + 1;
+            if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
+                c = es[child = right];
+            if (cmp.compare(x, (T) c) <= 0)
+                break;
+            es[k] = c;
+            k = child;
+        }
+        es[k] = x;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     * This classic algorithm due to Floyd (1964) is known to be O(size).
+     */
+    private void heapify() {
+        final Object[] es = queue;
+        int n = size, i = (n >>> 1) - 1;
+        final Comparator<? super E> cmp;
+        if ((cmp = comparator) == null)
+            for (; i >= 0; i--)
+                siftDownComparable(i, (E) es[i], es, n);
+        else
+            for (; i >= 0; i--)
+                siftDownUsingComparator(i, (E) es[i], es, n, cmp);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        int n, cap;
+        Object[] es;
+        while ((n = size) >= (cap = (es = queue).length))
+            tryGrow(es, cap);
+        try {
+            final Comparator<? super E> cmp;
+            if ((cmp = comparator) == null)
+                siftUpComparable(n, e, es);
+            else
+                siftUpUsingComparator(n, e, es, cmp);
+            size = n + 1;
+            notEmpty.signal();
+        } finally {
+            lock.unlock();
+        }
+        return true;
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        offer(e); // never need to block
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @param e the element to add
+     * @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(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
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e); // never need to block
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null)
+                notEmpty.await();
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null && nanos > 0)
+                nanos = notEmpty.awaitNanos(nanos);
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (E) queue[0];
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this queue,
+     * or {@code null} if this queue uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this queue,
+     *         or {@code null} if this queue uses the natural
+     *         ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return size;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code PriorityBlockingQueue} is not capacity constrained.
+     * @return {@code Integer.MAX_VALUE} always
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                if (o.equals(es[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     */
+    private void removeAt(int i) {
+        final Object[] es = queue;
+        final int n = size - 1;
+        if (n == i) // removed last element
+            es[i] = null;
+        else {
+            E moved = (E) es[n];
+            es[n] = null;
+            final Comparator<? super E> cmp;
+            if ((cmp = comparator) == null)
+                siftDownComparable(i, moved, es, n);
+            else
+                siftDownUsingComparator(i, moved, es, n, cmp);
+            if (es[i] == moved) {
+                if (cmp == null)
+                    siftUpComparable(i, moved, es);
+                else
+                    siftUpUsingComparator(i, moved, es, cmp);
+            }
+        }
+        size = n;
+    }
+
+    /**
+     * 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 and only 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) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int i = indexOf(o);
+            if (i == -1)
+                return false;
+            removeAt(i);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     *
+     * @param o element to be removed from this queue, if present
+     */
+    void removeEq(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++) {
+                if (o == es[i]) {
+                    removeAt(i);
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 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) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return indexOf(o) != -1;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            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 {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                es[i] = null;
+            size = 0;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return Arrays.copyOf(queue, size);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = size;
+            if (a.length < n)
+                // Make a new array of a's runtime type, but my contents:
+                return (T[]) Arrays.copyOf(queue, size, a.getClass());
+            System.arraycopy(queue, 0, a, 0, n);
+            if (a.length > n)
+                a[n] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The
+     * iterator does not return the elements in any particular order.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    final class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet = -1;     // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            return (E)array[lastRet = cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEq(array[lastRet]);
+            lastRet = -1;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Object[] es = array;
+            int i;
+            if ((i = cursor) < es.length) {
+                lastRet = -1;
+                cursor = es.length;
+                for (; i < es.length; i++)
+                    action.accept((E) es[i]);
+                lastRet = es.length - 1;
+            }
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * For compatibility with previous version of this class, elements
+     * are first copied to a java.util.PriorityQueue, which is then
+     * serialized.
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        lock.lock();
+        try {
+            // avoid zero capacity argument
+            q = new PriorityQueue<E>(Math.max(size, 1), comparator);
+            q.addAll(this);
+            s.defaultWriteObject();
+        } finally {
+            q = null;
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        try {
+            s.defaultReadObject();
+            int sz = q.size();
+            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, sz);
+            this.queue = new Object[Math.max(1, sz)];
+            comparator = q.comparator();
+            addAll(q);
+        } finally {
+            q = null;
+        }
+    }
+
+    /**
+     * Immutable snapshot spliterator that binds to elements "late".
+     */
+    final class PBQSpliterator implements Spliterator<E> {
+        Object[] array;        // null until late-bound-initialized
+        int index;
+        int fence;
+
+        PBQSpliterator() {}
+
+        PBQSpliterator(Object[] array, int index, int fence) {
+            this.array = array;
+            this.index = index;
+            this.fence = fence;
+        }
+
+        private int getFence() {
+            if (array == null)
+                fence = (array = toArray()).length;
+            return fence;
+        }
+
+        public PBQSpliterator trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PBQSpliterator(array, lo, index = mid);
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int hi = getFence(), lo = index;
+            final Object[] es = array;
+            index = hi;                 // ensure exhaustion
+            for (int i = lo; i < hi; i++)
+                action.accept((E) es[i]);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            if (getFence() > index && index >= 0) {
+                action.accept((E) array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() { return getFence() - index; }
+
+        public int characteristics() {
+            return (Spliterator.NONNULL |
+                    Spliterator.SIZED |
+                    Spliterator.SUBSIZED);
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     * The spliterator does not traverse elements in any particular order
+     * (the {@link Spliterator#ORDERED ORDERED} characteristic is not reported).
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new PBQSpliterator();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            final int end = size;
+            int i;
+            // Optimize for initial run of survivors
+            for (i = 0; i < end && !filter.test((E) es[i]); i++)
+                ;
+            if (i >= end)
+                return false;
+            // Tolerate predicates that reentrantly access the
+            // collection for read, so traverse once to find elements
+            // to delete, a second pass to physically expunge.
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test((E) es[i]))
+                    setBit(deathRow, i - beg);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            for (i = size = w; i < end; i++)
+                es[i] = null;
+            heapify();
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] es = queue;
+            for (int i = 0, n = size; i < n; i++)
+                action.accept((E) es[i]);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle ALLOCATIONSPINLOCK;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
+                                                 "allocationSpinLock",
+                                                 int.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/RecursiveAction.java b/android-35/java/util/concurrent/RecursiveAction.java
new file mode 100644
index 0000000..3378045
--- /dev/null
+++ b/android-35/java/util/concurrent/RecursiveAction.java
@@ -0,0 +1,198 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * 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:
+ *   static final 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
+ * @author Doug Lea
+ */
+public abstract class RecursiveAction extends ForkJoinTask<Void> {
+    private static final long serialVersionUID = 5232453952276485070L;
+
+    /**
+     * Constructor for subclasses to call.
+     */
+    public RecursiveAction() {}
+
+    /**
+     * 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/android-35/java/util/concurrent/RecursiveTask.java b/android-35/java/util/concurrent/RecursiveTask.java
new file mode 100644
index 0000000..3ba26c1
--- /dev/null
+++ b/android-35/java/util/concurrent/RecursiveTask.java
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * 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; }
+ *   protected 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
+ * @author Doug Lea
+ */
+public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
+    private static final long serialVersionUID = 5232453952276485270L;
+
+    /**
+     * Constructor for subclasses to call.
+     */
+    public RecursiveTask() {}
+
+    /**
+     * The result of the computation.
+     */
+    @SuppressWarnings("serial") // Conditionally serializable
+    V result;
+
+    /**
+     * The main computation performed by this task.
+     * @return the result of the computation
+     */
+    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/android-35/java/util/concurrent/RejectedExecutionException.java b/android-35/java/util/concurrent/RejectedExecutionException.java
new file mode 100644
index 0000000..87feef4
--- /dev/null
+++ b/android-35/java/util/concurrent/RejectedExecutionException.java
@@ -0,0 +1,91 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown by an {@link Executor} when a task cannot be
+ * accepted for execution.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class RejectedExecutionException extends RuntimeException {
+    private static final long serialVersionUID = -375805702767069545L;
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    public RejectedExecutionException() { }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message. The cause is not initialized, and may
+     * subsequently be initialized by a call to {@link
+     * #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    public RejectedExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified cause.  The detail message is set to {@code (cause ==
+     * null ? null : cause.toString())} (which typically contains
+     * the class and detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/android-35/java/util/concurrent/RejectedExecutionHandler.java b/android-35/java/util/concurrent/RejectedExecutionHandler.java
new file mode 100644
index 0000000..c1e314c
--- /dev/null
+++ b/android-35/java/util/concurrent/RejectedExecutionHandler.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface RejectedExecutionHandler {
+
+    /**
+     * Method that may be invoked by a {@link ThreadPoolExecutor} when
+     * {@link ThreadPoolExecutor#execute execute} cannot accept a
+     * task.  This may occur when no more threads or queue slots are
+     * available because their bounds would be exceeded, or upon
+     * shutdown of the Executor.
+     *
+     * <p>In the absence of other alternatives, the method may throw
+     * an unchecked {@link RejectedExecutionException}, which will be
+     * propagated to the caller of {@code execute}.
+     *
+     * @param r the runnable task requested to be executed
+     * @param executor the executor attempting to execute this task
+     * @throws RejectedExecutionException if there is no remedy
+     */
+    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
+}
diff --git a/android-35/java/util/concurrent/RunnableFuture.java b/android-35/java/util/concurrent/RunnableFuture.java
new file mode 100644
index 0000000..b6b088a
--- /dev/null
+++ b/android-35/java/util/concurrent/RunnableFuture.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link Future} that is {@link Runnable}. Successful execution of
+ * the {@code run} method causes completion of the {@code Future}
+ * and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableFuture<V> extends Runnable, Future<V> {
+    /**
+     * Sets this Future to the result of its computation
+     * unless it has been cancelled.
+     */
+    void run();
+}
diff --git a/android-35/java/util/concurrent/RunnableScheduledFuture.java b/android-35/java/util/concurrent/RunnableScheduledFuture.java
new file mode 100644
index 0000000..4f5ce1b
--- /dev/null
+++ b/android-35/java/util/concurrent/RunnableScheduledFuture.java
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ScheduledFuture} that is {@link Runnable}. Successful
+ * execution of the {@code run} method causes completion of the
+ * {@code Future} and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
+
+    /**
+     * Returns {@code true} if this task is periodic. A periodic task may
+     * re-run according to some schedule. A non-periodic task can be
+     * run only once.
+     *
+     * @return {@code true} if this task is periodic
+     */
+    boolean isPeriodic();
+}
diff --git a/android-35/java/util/concurrent/ScheduledExecutorService.java b/android-35/java/util/concurrent/ScheduledExecutorService.java
new file mode 100644
index 0000000..4d63ffa
--- /dev/null
+++ b/android-35/java/util/concurrent/ScheduledExecutorService.java
@@ -0,0 +1,209 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An {@link ExecutorService} that can schedule commands to run after a given
+ * delay, or to execute periodically.
+ *
+ * <p>The {@code schedule} methods create tasks with various delays
+ * and return a task object that can be used to cancel or check
+ * execution. The {@code scheduleAtFixedRate} and
+ * {@code scheduleWithFixedDelay} methods create and execute tasks
+ * that run periodically until cancelled.
+ *
+ * <p>Commands submitted using the {@link Executor#execute(Runnable)}
+ * and {@link ExecutorService} {@code submit} methods are scheduled
+ * with a requested delay of zero. Zero and negative delays (but not
+ * periods) are also allowed in {@code schedule} methods, and are
+ * treated as requests for immediate execution.
+ *
+ * <p>All {@code schedule} methods accept <em>relative</em> delays and
+ * periods as arguments, not absolute times or dates. It is a simple
+ * matter to transform an absolute time represented as a {@link
+ * java.util.Date} to the required form. For example, to schedule at
+ * a certain future {@code date}, you can use: {@code schedule(task,
+ * date.getTime() - System.currentTimeMillis(),
+ * TimeUnit.MILLISECONDS)}. Beware however that expiration of a
+ * relative delay need not coincide with the current {@code Date} at
+ * which the task is enabled due to network time synchronization
+ * protocols, clock drift, or other factors.
+ *
+ * <p>The {@link Executors} class provides convenient factory methods for
+ * the ScheduledExecutorService implementations provided in this package.
+ *
+ * <h2>Usage Example</h2>
+ *
+ * Here is a class with a method that sets up a ScheduledExecutorService
+ * to beep every ten seconds for an hour:
+ *
+ * <pre> {@code
+ * import static java.util.concurrent.TimeUnit.*;
+ * class BeeperControl {
+ *   private final ScheduledExecutorService scheduler =
+ *     Executors.newScheduledThreadPool(1);
+ *
+ *   public void beepForAnHour() {
+ *     Runnable beeper = () -> System.out.println("beep");
+ *     ScheduledFuture<?> beeperHandle =
+ *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
+ *     Runnable canceller = () -> beeperHandle.cancel(false);
+ *     scheduler.schedule(canceller, 1, HOURS);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ScheduledExecutorService extends ExecutorService {
+
+    /**
+     * Submits a one-shot task that becomes enabled after the given delay.
+     *
+     * @param command the task to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @return a ScheduledFuture representing pending completion of
+     *         the task and whose {@code get()} method will return
+     *         {@code null} upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay, TimeUnit unit);
+
+    /**
+     * Submits a value-returning one-shot task that becomes enabled
+     * after the given delay.
+     *
+     * @param callable the function to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @param <V> the type of the callable's result
+     * @return a ScheduledFuture that can be used to extract result or cancel
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if callable or unit is null
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay, TimeUnit unit);
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given period;
+     * that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param period the period between successive executions
+     * @param unit the time unit of the initialDelay and period parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     * @throws IllegalArgumentException if period less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit);
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given delay
+     * between the termination of one execution and the commencement of
+     * the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param delay the delay between the termination of one
+     * execution and the commencement of the next
+     * @param unit the time unit of the initialDelay and delay parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command or unit is null
+     * @throws IllegalArgumentException if delay less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit);
+
+}
diff --git a/android-35/java/util/concurrent/ScheduledFuture.java b/android-35/java/util/concurrent/ScheduledFuture.java
new file mode 100644
index 0000000..1c1efa4
--- /dev/null
+++ b/android-35/java/util/concurrent/ScheduledFuture.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A delayed result-bearing action that can be cancelled.
+ * Usually a scheduled future is the result of scheduling
+ * a task with a {@link ScheduledExecutorService}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future
+ */
+public interface ScheduledFuture<V> extends Delayed, Future<V> {
+}
diff --git a/android-35/java/util/concurrent/ScheduledThreadPoolExecutor.java b/android-35/java/util/concurrent/ScheduledThreadPoolExecutor.java
new file mode 100644
index 0000000..192df25
--- /dev/null
+++ b/android-35/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -0,0 +1,1356 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// omit class-level docs on setRemoveOnCancelPolicy()
+// END android-note
+
+/**
+ * A {@link ThreadPoolExecutor} that can additionally schedule
+ * commands to run after a given delay, or to execute periodically.
+ * This class is preferable to {@link java.util.Timer} when multiple
+ * worker threads are needed, or when the additional flexibility or
+ * capabilities of {@link ThreadPoolExecutor} (which this class
+ * extends) are required.
+ *
+ * <p>Delayed tasks execute no sooner than they are enabled, but
+ * without any real-time guarantees about when, after they are
+ * enabled, they will commence. Tasks scheduled for exactly the same
+ * execution time are enabled in first-in-first-out (FIFO) order of
+ * submission.
+ *
+ * <p>When a submitted task is cancelled before it is run, execution
+ * is suppressed.  By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay elapses.
+ * While this enables further inspection and monitoring, it may also
+ * cause unbounded retention of cancelled tasks.
+ *
+ * <p>Successive executions of a periodic task scheduled via
+ * {@link #scheduleAtFixedRate scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
+ * do not overlap. While different executions may be performed by
+ * different threads, the effects of prior executions
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those of subsequent ones.
+ *
+ * <p>While this class inherits from {@link ThreadPoolExecutor}, a few
+ * of the inherited tuning methods are not useful for it. In
+ * particular, because it acts as a fixed-sized pool using
+ * {@code corePoolSize} threads and an unbounded queue, adjustments
+ * to {@code maximumPoolSize} have no useful effect. Additionally, it
+ * is almost never a good idea to set {@code corePoolSize} to zero or
+ * use {@code allowCoreThreadTimeOut} because this may leave the pool
+ * without threads to handle tasks once they become eligible to run.
+ *
+ * <p>As with {@code ThreadPoolExecutor}, if not otherwise specified,
+ * this class uses {@link Executors#defaultThreadFactory} as the
+ * default thread factory, and {@link ThreadPoolExecutor.AbortPolicy}
+ * as the default rejected execution handler.
+ *
+ * <p><b>Extension notes:</b> This class overrides the
+ * {@link ThreadPoolExecutor#execute(Runnable) execute} and
+ * {@link AbstractExecutorService#submit(Runnable) submit}
+ * methods to generate internal {@link ScheduledFuture} objects to
+ * control per-task delays and scheduling.  To preserve
+ * functionality, any further overrides of these methods in
+ * subclasses must invoke superclass versions, which effectively
+ * disables additional task customization.  However, this class
+ * provides alternative protected extension method
+ * {@code decorateTask} (one version each for {@code Runnable} and
+ * {@code Callable}) that can be used to customize the concrete task
+ * types used to execute commands entered via {@code execute},
+ * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate},
+ * and {@code scheduleWithFixedDelay}.  By default, a
+ * {@code ScheduledThreadPoolExecutor} uses a task type extending
+ * {@link FutureTask}. However, this may be modified or replaced using
+ * subclasses of the form:
+ *
+ * <pre> {@code
+ * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Runnable r, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(r, task);
+ *   }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Callable<V> c, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(c, task);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ScheduledThreadPoolExecutor
+        extends ThreadPoolExecutor
+        implements ScheduledExecutorService {
+
+    /*
+     * This class specializes ThreadPoolExecutor implementation by
+     *
+     * 1. Using a custom task type ScheduledFutureTask, even for tasks
+     *    that don't require scheduling because they are submitted
+     *    using ExecutorService rather than ScheduledExecutorService
+     *    methods, which are treated as tasks with a delay of zero.
+     *
+     * 2. Using a custom queue (DelayedWorkQueue), a variant of
+     *    unbounded DelayQueue. The lack of capacity constraint and
+     *    the fact that corePoolSize and maximumPoolSize are
+     *    effectively identical simplifies some execution mechanics
+     *    (see delayedExecute) compared to ThreadPoolExecutor.
+     *
+     * 3. Supporting optional run-after-shutdown parameters, which
+     *    leads to overrides of shutdown methods to remove and cancel
+     *    tasks that should NOT be run after shutdown, as well as
+     *    different recheck logic when task (re)submission overlaps
+     *    with a shutdown.
+     *
+     * 4. Task decoration methods to allow interception and
+     *    instrumentation, which are needed because subclasses cannot
+     *    otherwise override submit methods to get this effect. These
+     *    don't have any impact on pool control logic though.
+     */
+
+    /**
+     * False if should cancel/suppress periodic tasks on shutdown.
+     */
+    private volatile boolean continueExistingPeriodicTasksAfterShutdown;
+
+    // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+    /**
+     * False if should cancel non-periodic tasks on shutdown.
+     */
+    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
+
+    /**
+     * True if ScheduledFutureTask.cancel should remove from queue.
+     */
+    volatile boolean removeOnCancel;
+
+    /**
+     * Sequence number to break scheduling ties, and in turn to
+     * guarantee FIFO order among tied entries.
+     */
+    private static final AtomicLong sequencer = new AtomicLong();
+
+    private class ScheduledFutureTask<V>
+            extends FutureTask<V> implements RunnableScheduledFuture<V> {
+
+        /** Sequence number to break ties FIFO */
+        private final long sequenceNumber;
+
+        /** The nanoTime-based time when the task is enabled to execute. */
+        private volatile long time;
+
+        /**
+         * Period for repeating tasks, in nanoseconds.
+         * A positive value indicates fixed-rate execution.
+         * A negative value indicates fixed-delay execution.
+         * A value of 0 indicates a non-repeating (one-shot) task.
+         */
+        private final long period;
+
+        /** The actual task to be re-enqueued by reExecutePeriodic */
+        RunnableScheduledFuture<V> outerTask = this;
+
+        /**
+         * Index into delay queue, to support faster cancellation.
+         */
+        int heapIndex;
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a periodic action with given nanoTime-based initial
+         * trigger time and period.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long period, long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = period;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Callable<V> callable, long triggerTime,
+                            long sequenceNumber) {
+            super(callable);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        public long getDelay(TimeUnit unit) {
+            return unit.convert(time - System.nanoTime(), NANOSECONDS);
+        }
+
+        public int compareTo(Delayed other) {
+            if (other == this) // compare zero if same object
+                return 0;
+            if (other instanceof ScheduledFutureTask) {
+                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
+                long diff = time - x.time;
+                if (diff < 0)
+                    return -1;
+                else if (diff > 0)
+                    return 1;
+                else if (sequenceNumber < x.sequenceNumber)
+                    return -1;
+                else
+                    return 1;
+            }
+            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
+            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+        }
+
+        /**
+         * Returns {@code true} if this is a periodic (not a one-shot) action.
+         *
+         * @return {@code true} if periodic
+         */
+        public boolean isPeriodic() {
+            return period != 0;
+        }
+
+        /**
+         * Sets the next time to run for a periodic task.
+         */
+        private void setNextRunTime() {
+            long p = period;
+            if (p > 0)
+                time += p;
+            else
+                time = triggerTime(-p);
+        }
+
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            // The racy read of heapIndex below is benign:
+            // if heapIndex < 0, then OOTA guarantees that we have surely
+            // been removed; else we recheck under lock in remove()
+            boolean cancelled = super.cancel(mayInterruptIfRunning);
+            if (cancelled && removeOnCancel && heapIndex >= 0)
+                remove(this);
+            return cancelled;
+        }
+
+        /**
+         * Overrides FutureTask version so as to reset/requeue if periodic.
+         */
+        public void run() {
+            if (!canRunInCurrentRunState(this))
+                cancel(false);
+            else if (!isPeriodic())
+                super.run();
+            else if (super.runAndReset()) {
+                setNextRunTime();
+                reExecutePeriodic(outerTask);
+            }
+        }
+    }
+
+    /**
+     * Returns true if can run a task given current run state and
+     * run-after-shutdown parameters.
+     */
+    boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
+        if (!isShutdown())
+            return true;
+        if (isStopped())
+            return false;
+        return task.isPeriodic()
+            ? continueExistingPeriodicTasksAfterShutdown
+            : (executeExistingDelayedTasksAfterShutdown
+            // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+            //   || task.getDelay(NANOSECONDS) <= 0);
+              );
+    }
+
+    /**
+     * Main execution method for delayed or periodic tasks.  If pool
+     * is shut down, rejects the task. Otherwise adds task to queue
+     * and starts a thread, if necessary, to run it.  (We cannot
+     * prestart the thread to run the task because the task (probably)
+     * shouldn't be run yet.)  If the pool is shut down while the task
+     * is being added, cancel and remove it if required by state and
+     * run-after-shutdown parameters.
+     *
+     * @param task the task
+     */
+    private void delayedExecute(RunnableScheduledFuture<?> task) {
+        if (isShutdown())
+            reject(task);
+        else {
+            super.getQueue().add(task);
+            if (!canRunInCurrentRunState(task) && remove(task))
+                task.cancel(false);
+            else
+                ensurePrestart();
+        }
+    }
+
+    /**
+     * Requeues a periodic task unless current run state precludes it.
+     * Same idea as delayedExecute except drops task rather than rejecting.
+     *
+     * @param task the task
+     */
+    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
+        if (canRunInCurrentRunState(task)) {
+            super.getQueue().add(task);
+            if (canRunInCurrentRunState(task) || !remove(task)) {
+                ensurePrestart();
+                return;
+            }
+        }
+        task.cancel(false);
+    }
+
+    /**
+     * Cancels and clears the queue of all tasks that should not be run
+     * due to shutdown policy.  Invoked within super.shutdown.
+     */
+    @Override void onShutdown() {
+        BlockingQueue<Runnable> q = super.getQueue();
+        boolean keepDelayed =
+            getExecuteExistingDelayedTasksAfterShutdownPolicy();
+        boolean keepPeriodic =
+            getContinueExistingPeriodicTasksAfterShutdownPolicy();
+        // Traverse snapshot to avoid iterator exceptions
+        // TODO: implement and use efficient removeIf
+        // super.getQueue().removeIf(...);
+        for (Object e : q.toArray()) {
+            if (e instanceof RunnableScheduledFuture) {
+                RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e;
+                if ((t.isPeriodic()
+                     ? !keepPeriodic
+                     // Android-changed: Preserving behaviour on expired tasks (b/202927404)
+                     // : (!keepDelayed && t.getDelay(NANOSECONDS) > 0))
+                     : !keepDelayed)
+                    || t.isCancelled()) { // also remove if already cancelled
+                    if (q.remove(t))
+                        t.cancel(false);
+                }
+            }
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a runnable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param runnable the submitted Runnable
+     * @param task the task created to execute the runnable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the runnable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Runnable runnable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a callable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param callable the submitted Callable
+     * @param task the task created to execute the callable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the callable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Callable<V> callable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * The default keep-alive time for pool threads.
+     *
+     * Normally, this value is unused because all pool threads will be
+     * core threads, but if a user creates a pool with a corePoolSize
+     * of zero (against our advice), we keep a thread alive as long as
+     * there are queued tasks.  If the keep alive time is zero (the
+     * historic value), we end up hot-spinning in getTask, wasting a
+     * CPU.  But on the other hand, if we set the value too high, and
+     * users create a one-shot pool which they don't cleanly shutdown,
+     * the pool's non-daemon threads will prevent JVM termination.  A
+     * small but non-zero value (relative to a JVM's lifetime) seems
+     * best.
+     */
+    private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given core pool size.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue());
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), handler);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} or
+     *         {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory, handler);
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    private long triggerTime(long delay, TimeUnit unit) {
+        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    long triggerTime(long delay) {
+        return System.nanoTime() +
+            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
+    }
+
+    /**
+     * Constrains the values of all delays in the queue to be within
+     * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
+     * This may occur if a task is eligible to be dequeued, but has
+     * not yet been, while some other task is added with a delay of
+     * Long.MAX_VALUE.
+     */
+    private long overflowFree(long delay) {
+        Delayed head = (Delayed) super.getQueue().peek();
+        if (head != null) {
+            long headDelay = head.getDelay(NANOSECONDS);
+            if (headDelay < 0 && (delay - headDelay < 0))
+                delay = Long.MAX_VALUE + headDelay;
+        }
+        return delay;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay,
+                                       TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<Void> t = decorateTask(command,
+            new ScheduledFutureTask<Void>(command, null,
+                                          triggerTime(delay, unit),
+                                          sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay,
+                                           TimeUnit unit) {
+        if (callable == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<V> t = decorateTask(callable,
+            new ScheduledFutureTask<V>(callable,
+                                       triggerTime(delay, unit),
+                                       sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given period;
+     * that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>Method {@link #shutdown} is called and the {@linkplain
+     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+     * whether to continue after shutdown} is not set true, or method
+     * {@link #shutdownNow} is called; also resulting in task
+     * cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (period <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          unit.toNanos(period),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * Submits a periodic action that becomes enabled first after the
+     * given initial delay, and subsequently with the given delay
+     * between the termination of one execution and the commencement of
+     * the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>Method {@link #shutdown} is called and the {@linkplain
+     * #getContinueExistingPeriodicTasksAfterShutdownPolicy policy on
+     * whether to continue after shutdown} is not set true, or method
+     * {@link #shutdownNow} is called; also resulting in task
+     * cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will throw
+     * {@link ExecutionException}, holding the exception as its cause.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (delay <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          -unit.toNanos(delay),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * Executes {@code command} with zero required delay.
+     * This has effect equivalent to
+     * {@link #schedule(Runnable,long,TimeUnit) schedule(command, 0, anyUnit)}.
+     * Note that inspections of the queue and of the list returned by
+     * {@code shutdownNow} will access the zero-delayed
+     * {@link ScheduledFuture}, not the {@code command} itself.
+     *
+     * <p>A consequence of the use of {@code ScheduledFuture} objects is
+     * that {@link ThreadPoolExecutor#afterExecute afterExecute} is always
+     * called with a null second {@code Throwable} argument, even if the
+     * {@code command} terminated abruptly.  Instead, the {@code Throwable}
+     * thrown by such a task can be obtained via {@link Future#get}.
+     *
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution because the
+     *         executor has been shut down
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void execute(Runnable command) {
+        schedule(command, 0, NANOSECONDS);
+    }
+
+    // Override AbstractExecutorService methods
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * Sets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, executions will continue until {@code shutdownNow}
+     * or the policy is set to {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @param value if {@code true}, continue after shutdown, else don't
+     * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
+        continueExistingPeriodicTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, executions will continue until {@code shutdownNow}
+     * or the policy is set to {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @return {@code true} if will continue after shutdown
+     * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
+        return continueExistingPeriodicTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @param value if {@code true}, execute after shutdown, else don't
+     * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) {
+        executeExistingDelayedTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @return {@code true} if will execute after shutdown
+     * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
+        return executeExistingDelayedTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @param value if {@code true}, remove on cancellation, else don't
+     * @see #getRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public void setRemoveOnCancelPolicy(boolean value) {
+        removeOnCancel = value;
+    }
+
+    /**
+     * Gets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @return {@code true} if cancelled tasks are immediately removed
+     *         from the queue
+     * @see #setRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public boolean getRemoveOnCancelPolicy() {
+        return removeOnCancel;
+    }
+
+    /**
+     * 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.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     *
+     * <p>If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy}
+     * has been set {@code false}, existing delayed tasks whose delays
+     * have not yet elapsed are cancelled.  And unless the {@code
+     * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set
+     * {@code true}, future executions of existing periodic tasks will
+     * be cancelled.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public void shutdown() {
+        super.shutdown();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution.
+     *         Each element of this list is a {@link ScheduledFuture}.
+     *         For tasks submitted via one of the {@code schedule}
+     *         methods, the element will be identical to the returned
+     *         {@code ScheduledFuture}.  For tasks submitted using
+     *         {@link #execute execute}, the element will be a
+     *         zero-delay {@code ScheduledFuture}.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public List<Runnable> shutdownNow() {
+        return super.shutdownNow();
+    }
+
+    /**
+     * Returns the task queue used by this executor.  Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * <p>Each element of this queue is a {@link ScheduledFuture}.
+     * For tasks submitted via one of the {@code schedule} methods, the
+     * element will be identical to the returned {@code ScheduledFuture}.
+     * For tasks submitted using {@link #execute execute}, the element
+     * will be a zero-delay {@code ScheduledFuture}.
+     *
+     * <p>Iteration over this queue is <em>not</em> guaranteed to traverse
+     * tasks in the order in which they will execute.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return super.getQueue();
+    }
+
+    /**
+     * Specialized delay queue. To mesh with TPE declarations, this
+     * class must be declared as a BlockingQueue<Runnable> even though
+     * it can only hold RunnableScheduledFutures.
+     */
+    static class DelayedWorkQueue extends AbstractQueue<Runnable>
+        implements BlockingQueue<Runnable> {
+
+        /*
+         * A DelayedWorkQueue is based on a heap-based data structure
+         * like those in DelayQueue and PriorityQueue, except that
+         * every ScheduledFutureTask also records its index into the
+         * heap array. This eliminates the need to find a task upon
+         * cancellation, greatly speeding up removal (down from O(n)
+         * to O(log n)), and reducing garbage retention that would
+         * otherwise occur by waiting for the element to rise to top
+         * before clearing. But because the queue may also hold
+         * RunnableScheduledFutures that are not ScheduledFutureTasks,
+         * we are not guaranteed to have such indices available, in
+         * which case we fall back to linear search. (We expect that
+         * most tasks will not be decorated, and that the faster cases
+         * will be much more common.)
+         *
+         * All heap operations must record index changes -- mainly
+         * within siftUp and siftDown. Upon removal, a task's
+         * heapIndex is set to -1. Note that ScheduledFutureTasks can
+         * appear at most once in the queue (this need not be true for
+         * other kinds of tasks or work queues), so are uniquely
+         * identified by heapIndex.
+         */
+
+        private static final int INITIAL_CAPACITY = 16;
+        private RunnableScheduledFuture<?>[] queue =
+            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
+        private final ReentrantLock lock = new ReentrantLock();
+        private int size;
+
+        /**
+         * Thread designated to wait for the task at the head of the
+         * queue.  This variant of the Leader-Follower pattern
+         * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+         * minimize unnecessary timed waiting.  When a thread becomes
+         * the leader, it waits only for the next delay to elapse, but
+         * other threads await indefinitely.  The leader thread must
+         * signal some other thread before returning from take() or
+         * poll(...), unless some other thread becomes leader in the
+         * interim.  Whenever the head of the queue is replaced with a
+         * task with an earlier expiration time, the leader field is
+         * invalidated by being reset to null, and some waiting
+         * thread, but not necessarily the current leader, is
+         * signalled.  So waiting threads must be prepared to acquire
+         * and lose leadership while waiting.
+         */
+        private Thread leader;
+
+        /**
+         * Condition signalled when a newer task becomes available at the
+         * head of the queue or a new thread may need to become leader.
+         */
+        private final Condition available = lock.newCondition();
+
+        /**
+         * Sets f's heapIndex if it is a ScheduledFutureTask.
+         */
+        private static void setIndex(RunnableScheduledFuture<?> f, int idx) {
+            if (f instanceof ScheduledFutureTask)
+                ((ScheduledFutureTask)f).heapIndex = idx;
+        }
+
+        /**
+         * Sifts element added at bottom up to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftUp(int k, RunnableScheduledFuture<?> key) {
+            while (k > 0) {
+                int parent = (k - 1) >>> 1;
+                RunnableScheduledFuture<?> e = queue[parent];
+                if (key.compareTo(e) >= 0)
+                    break;
+                queue[k] = e;
+                setIndex(e, k);
+                k = parent;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Sifts element added at top down to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftDown(int k, RunnableScheduledFuture<?> key) {
+            int half = size >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                RunnableScheduledFuture<?> c = queue[child];
+                int right = child + 1;
+                if (right < size && c.compareTo(queue[right]) > 0)
+                    c = queue[child = right];
+                if (key.compareTo(c) <= 0)
+                    break;
+                queue[k] = c;
+                setIndex(c, k);
+                k = child;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Resizes the heap array.  Call only when holding lock.
+         */
+        private void grow() {
+            int oldCapacity = queue.length;
+            int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
+            if (newCapacity < 0) // overflow
+                newCapacity = Integer.MAX_VALUE;
+            queue = Arrays.copyOf(queue, newCapacity);
+        }
+
+        /**
+         * Finds index of given object, or -1 if absent.
+         */
+        private int indexOf(Object x) {
+            if (x != null) {
+                if (x instanceof ScheduledFutureTask) {
+                    int i = ((ScheduledFutureTask) x).heapIndex;
+                    // Sanity check; x could conceivably be a
+                    // ScheduledFutureTask from some other pool.
+                    if (i >= 0 && i < size && queue[i] == x)
+                        return i;
+                } else {
+                    for (int i = 0; i < size; i++)
+                        if (x.equals(queue[i]))
+                            return i;
+                }
+            }
+            return -1;
+        }
+
+        public boolean contains(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return indexOf(x) != -1;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean remove(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = indexOf(x);
+                if (i < 0)
+                    return false;
+
+                setIndex(queue[i], -1);
+                int s = --size;
+                RunnableScheduledFuture<?> replacement = queue[s];
+                queue[s] = null;
+                if (s != i) {
+                    siftDown(i, replacement);
+                    if (queue[i] == replacement)
+                        siftUp(i, replacement);
+                }
+                return true;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int size() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return size;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public int remainingCapacity() {
+            return Integer.MAX_VALUE;
+        }
+
+        public RunnableScheduledFuture<?> peek() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return queue[0];
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean offer(Runnable x) {
+            if (x == null)
+                throw new NullPointerException();
+            RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = size;
+                if (i >= queue.length)
+                    grow();
+                size = i + 1;
+                if (i == 0) {
+                    queue[0] = e;
+                    setIndex(e, 0);
+                } else {
+                    siftUp(i, e);
+                }
+                if (queue[0] == e) {
+                    leader = null;
+                    available.signal();
+                }
+            } finally {
+                lock.unlock();
+            }
+            return true;
+        }
+
+        public void put(Runnable e) {
+            offer(e);
+        }
+
+        public boolean add(Runnable e) {
+            return offer(e);
+        }
+
+        public boolean offer(Runnable e, long timeout, TimeUnit unit) {
+            return offer(e);
+        }
+
+        /**
+         * Performs common bookkeeping for poll and take: Replaces
+         * first element with last and sifts it down.  Call only when
+         * holding lock.
+         * @param f the task to remove and return
+         */
+        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
+            int s = --size;
+            RunnableScheduledFuture<?> x = queue[s];
+            queue[s] = null;
+            if (s != 0)
+                siftDown(0, x);
+            setIndex(f, -1);
+            return f;
+        }
+
+        public RunnableScheduledFuture<?> poll() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first = queue[0];
+                return (first == null || first.getDelay(NANOSECONDS) > 0)
+                    ? null
+                    : finishPoll(first);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public RunnableScheduledFuture<?> take() throws InterruptedException {
+            final ReentrantLock lock = this.lock;
+            lock.lockInterruptibly();
+            try {
+                for (;;) {
+                    RunnableScheduledFuture<?> first = queue[0];
+                    if (first == null)
+                        available.await();
+                    else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        first = null; // don't retain ref while waiting
+                        if (leader != null)
+                            available.await();
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                available.awaitNanos(delay);
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        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];
+                    if (first == null) {
+                        if (nanos <= 0L)
+                            return null;
+                        else
+                            nanos = available.awaitNanos(nanos);
+                    } else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        if (nanos <= 0L)
+                            return null;
+                        first = null; // don't retain ref while waiting
+                        if (nanos < delay || leader != null)
+                            nanos = available.awaitNanos(nanos);
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                long timeLeft = available.awaitNanos(delay);
+                                nanos -= delay - timeLeft;
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        public void clear() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                for (int i = 0; i < size; i++) {
+                    RunnableScheduledFuture<?> t = queue[i];
+                    if (t != null) {
+                        queue[i] = null;
+                        setIndex(t, -1);
+                    }
+                }
+                size = 0;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int drainTo(Collection<? super Runnable> c) {
+            return drainTo(c, Integer.MAX_VALUE);
+        }
+
+        public int drainTo(Collection<? super Runnable> c, int maxElements) {
+            Objects.requireNonNull(c);
+            if (c == this)
+                throw new IllegalArgumentException();
+            if (maxElements <= 0)
+                return 0;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int n = 0;
+                for (RunnableScheduledFuture<?> first;
+                     n < maxElements
+                         && (first = queue[0]) != null
+                         && first.getDelay(NANOSECONDS) <= 0;) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Object[] toArray() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return Arrays.copyOf(queue, size, Object[].class);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                if (a.length < size)
+                    return (T[]) Arrays.copyOf(queue, size, a.getClass());
+                System.arraycopy(queue, 0, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Iterator<Runnable> iterator() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return new Itr(Arrays.copyOf(queue, size));
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Snapshot iterator that works off copy of underlying q array.
+         */
+        private class Itr implements Iterator<Runnable> {
+            final RunnableScheduledFuture<?>[] array;
+            int cursor;        // index of next element to return; initially 0
+            int lastRet = -1;  // index of last element returned; -1 if no such
+
+            Itr(RunnableScheduledFuture<?>[] array) {
+                this.array = array;
+            }
+
+            public boolean hasNext() {
+                return cursor < array.length;
+            }
+
+            public Runnable next() {
+                if (cursor >= array.length)
+                    throw new NoSuchElementException();
+                return array[lastRet = cursor++];
+            }
+
+            public void remove() {
+                if (lastRet < 0)
+                    throw new IllegalStateException();
+                DelayedWorkQueue.this.remove(array[lastRet]);
+                lastRet = -1;
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/Semaphore.java b/android-35/java/util/concurrent/Semaphore.java
new file mode 100644
index 0000000..5c29965
--- /dev/null
+++ b/android-35/java/util/concurrent/Semaphore.java
@@ -0,0 +1,720 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A counting semaphore.  Conceptually, a semaphore maintains a set of
+ * permits.  Each {@link #acquire} blocks if necessary until a permit is
+ * available, and then takes it.  Each {@link #release} adds a permit,
+ * potentially releasing a blocking acquirer.
+ * However, no actual permit objects are used; the {@code Semaphore} just
+ * keeps a count of the number available and acts accordingly.
+ *
+ * <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> {@code
+ * class Pool {
+ *   private static final int MAX_AVAILABLE = 100;
+ *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
+ *
+ *   public Object getItem() throws InterruptedException {
+ *     available.acquire();
+ *     return getNextAvailableItem();
+ *   }
+ *
+ *   public void putItem(Object x) {
+ *     if (markAsUnused(x))
+ *       available.release();
+ *   }
+ *
+ *   // Not a particularly efficient data structure; just for demo
+ *
+ *   protected Object[] items = ...; // whatever kinds of items being managed
+ *   protected boolean[] used = new boolean[MAX_AVAILABLE];
+ *
+ *   protected synchronized Object getNextAvailableItem() {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (!used[i]) {
+ *         used[i] = true;
+ *         return items[i];
+ *       }
+ *     }
+ *     return null; // not reached
+ *   }
+ *
+ *   protected synchronized boolean markAsUnused(Object item) {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (item == items[i]) {
+ *         if (used[i]) {
+ *           used[i] = false;
+ *           return true;
+ *         } else
+ *           return false;
+ *       }
+ *     }
+ *     return false;
+ *   }
+ * }}</pre>
+ *
+ * <p>Before obtaining an item each thread must acquire a permit from
+ * the semaphore, guaranteeing that an item is available for use. When
+ * the thread has finished with the item it is returned back to the
+ * pool and a permit is returned to the semaphore, allowing another
+ * thread to acquire that item.  Note that no synchronization lock is
+ * held when {@link #acquire} is called as that would prevent an item
+ * from being returned to the pool.  The semaphore encapsulates the
+ * synchronization needed to restrict access to the pool, separately
+ * from any synchronization needed to maintain the consistency of the
+ * pool itself.
+ *
+ * <p>A semaphore initialized to one, and which is used such that it
+ * only has at most one permit available, can serve as a mutual
+ * exclusion lock.  This is more commonly known as a <em>binary
+ * semaphore</em>, because it only has two states: one permit
+ * available, or zero permits available.  When used in this way, the
+ * binary semaphore has the property (unlike many {@link java.util.concurrent.locks.Lock}
+ * implementations), that the &quot;lock&quot; can be released by a
+ * thread other than the owner (as semaphores have no notion of
+ * ownership).  This can be useful in some specialized contexts, such
+ * as deadlock recovery.
+ *
+ * <p>The constructor for this class optionally accepts a
+ * <em>fairness</em> parameter. When set false, this class makes no
+ * guarantees about the order in which threads acquire permits. In
+ * particular, <em>barging</em> is permitted, that is, a thread
+ * invoking {@link #acquire} can be allocated a permit ahead of a
+ * thread that has been waiting - logically the new thread places itself at
+ * the head of the queue of waiting threads. When fairness is set true, the
+ * semaphore guarantees that threads invoking any of the {@link
+ * #acquire() acquire} methods are selected to obtain permits in the order in
+ * which their invocation of those methods was processed
+ * (first-in-first-out; FIFO). Note that FIFO ordering necessarily
+ * applies to specific internal points of execution within these
+ * methods.  So, it is possible for one thread to invoke
+ * {@code acquire} before another, but reach the ordering point after
+ * the other, and similarly upon return from the method.
+ * Also note that the untimed {@link #tryAcquire() tryAcquire} methods do not
+ * honor the fairness setting, but will take any permits that are
+ * available.
+ *
+ * <p>Generally, semaphores used to control resource access should be
+ * initialized as fair, to ensure that no thread is starved out from
+ * accessing a resource. When using semaphores for other kinds of
+ * synchronization control, the throughput advantages of non-fair
+ * ordering often outweigh fairness considerations.
+ *
+ * <p>This class also provides convenience methods to {@link
+ * #acquire(int) acquire} and {@link #release(int) release} multiple
+ * permits at a time. These methods are generally more efficient and
+ * effective than loops. However, they do not establish any preference
+ * order. For example, if thread A invokes {@code s.acquire(3}) and
+ * thread B invokes {@code s.acquire(2)}, and two permits become
+ * available, then there is no guarantee that thread B will obtain
+ * them unless its acquire came first and Semaphore {@code s} is in
+ * fair mode.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * a "release" method such as {@code release()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful "acquire" method such as {@code acquire()}
+ * in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Semaphore implements java.io.Serializable {
+    private static final long serialVersionUID = -3222578661600680210L;
+    /** All mechanics via AbstractQueuedSynchronizer subclass */
+    private final Sync sync;
+
+    /**
+     * Synchronization implementation for semaphore.  Uses AQS state
+     * to represent permits. Subclassed into fair and nonfair
+     * versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 1192457210091910933L;
+
+        Sync(int permits) {
+            setState(permits);
+        }
+
+        final int getPermits() {
+            return getState();
+        }
+
+        final int nonfairTryAcquireShared(int acquires) {
+            for (;;) {
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+
+        protected final boolean tryReleaseShared(int releases) {
+            for (;;) {
+                int current = getState();
+                int next = current + releases;
+                if (next < current) // overflow
+                    throw new Error("Maximum permit count exceeded");
+                if (compareAndSetState(current, next))
+                    return true;
+            }
+        }
+
+        final void reducePermits(int reductions) {
+            for (;;) {
+                int current = getState();
+                int next = current - reductions;
+                if (next > current) // underflow
+                    throw new Error("Permit count underflow");
+                if (compareAndSetState(current, next))
+                    return;
+            }
+        }
+
+        final int drainPermits() {
+            for (;;) {
+                int current = getState();
+                if (current == 0 || compareAndSetState(current, 0))
+                    return current;
+            }
+        }
+    }
+
+    /**
+     * NonFair version
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -2694183684443567898L;
+
+        NonfairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return nonfairTryAcquireShared(acquires);
+        }
+    }
+
+    /**
+     * Fair version
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = 2014338818796000944L;
+
+        FairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            for (;;) {
+                if (hasQueuedPredecessors())
+                    return -1;
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and nonfair fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     */
+    public Semaphore(int permits) {
+        sync = new NonfairSync(permits);
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and the given fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     * @param fair {@code true} if this semaphore will guarantee
+     *        first-in first-out granting of permits under contention,
+     *        else {@code false}
+     */
+    public Semaphore(int permits, boolean fair) {
+        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void acquire() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for a permit then it will continue to wait, but the
+     * time at which the thread is assigned a permit may change compared to
+     * the time it would have received the permit had no interruption
+     * occurred.  When the thread does return from this method its interrupt
+     * status will be set.
+     */
+    public void acquireUninterruptibly() {
+        sync.acquireShared(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, only if one is available at the
+     * time of invocation.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>Even when this semaphore has been set to use a
+     * fair ordering policy, a call to {@code tryAcquire()} <em>will</em>
+     * immediately acquire a permit if one is available, whether or not
+     * other threads are currently waiting.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting, then use
+     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS)}
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         otherwise
+     */
+    public boolean tryAcquire() {
+        return sync.nonfairTryAcquireShared(1) >= 0;
+    }
+
+    /**
+     * Acquires a permit from this semaphore, if one becomes available
+     * within the given waiting time and the current thread has not
+     * been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If a permit is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait for a permit
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         if the waiting time elapsed before a permit was acquired
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public boolean tryAcquire(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases a permit, returning it to the semaphore.
+     *
+     * <p>Releases a permit, increasing the number of available permits by
+     * one.  If any threads are trying to acquire a permit, then one is
+     * selected and given the permit that was just released.  That thread
+     * is (re)enabled for thread scheduling purposes.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link #acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     */
+    public void release() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available,
+     * or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquire();} except
+     * that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread are instead
+     * assigned to other threads trying to acquire permits, as if
+     * permits had been made available by a call to {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquire(int permits) throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireSharedInterruptibly(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
+     * except that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for permits then it will continue to wait and its
+     * position in the queue is not affected.  When the thread does return
+     * from this method its interrupt status will be set.
+     *
+     * @param permits the number of permits to acquire
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquireUninterruptibly(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireShared(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, only
+     * if all are available at the time of invocation.
+     *
+     * <p>Acquires the given number of permits, if they are available, and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then this method will return
+     * immediately with the value {@code false} and the number of available
+     * permits is unchanged.
+     *
+     * <p>Even when this semaphore has been set to use a fair ordering
+     * policy, a call to {@code tryAcquire} <em>will</em>
+     * immediately acquire a permit if one is available, whether or
+     * not other threads are currently waiting.  This
+     * &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to
+     * honor the fairness setting, then use {@link #tryAcquire(int,
+     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS)}
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @param permits the number of permits to acquire
+     * @return {@code true} if the permits were acquired and
+     *         {@code false} otherwise
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.nonfairTryAcquireShared(permits) >= 0;
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, if all
+     * become available within the given waiting time and the current
+     * thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the permits are acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire the permits,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread, are instead
+     * assigned to other threads trying to acquire permits, as if
+     * the permits had been made available by a call to {@link #release()}.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.  Any permits that were to be assigned to this
+     * thread, are instead assigned to other threads trying to acquire
+     * permits, as if the permits had been made available by a call to
+     * {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @param timeout the maximum time to wait for the permits
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if all permits were acquired and {@code false}
+     *         if the waiting time elapsed before all permits were acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases the given number of permits, returning them to the semaphore.
+     *
+     * <p>Releases the given number of permits, increasing the number of
+     * available permits by that amount.
+     * If any threads are trying to acquire permits, then one thread
+     * is selected and given the permits that were just released.
+     * If the number of available permits satisfies that thread's request
+     * then that thread is (re)enabled for thread scheduling purposes;
+     * otherwise the thread will wait until sufficient permits are available.
+     * If there are still permits available
+     * after this thread's request has been satisfied, then those permits
+     * are assigned in turn to other threads trying to acquire permits.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link Semaphore#acquire acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     *
+     * @param permits the number of permits to release
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void release(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.releaseShared(permits);
+    }
+
+    /**
+     * Returns the current number of permits available in this semaphore.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the number of permits available in this semaphore
+     */
+    public int availablePermits() {
+        return sync.getPermits();
+    }
+
+    /**
+     * Acquires and returns all permits that are immediately
+     * available, or if negative permits are available, releases them.
+     * Upon return, zero permits are available.
+     *
+     * @return the number of permits acquired or, if negative, the
+     * number released
+     */
+    public int drainPermits() {
+        return sync.drainPermits();
+    }
+
+    /**
+     * Shrinks the number of available permits by the indicated
+     * reduction. This method can be useful in subclasses that use
+     * semaphores to track resources that become unavailable. This
+     * method differs from {@code acquire} in that it does not block
+     * waiting for permits to become available.
+     *
+     * @param reduction the number of permits to remove
+     * @throws IllegalArgumentException if {@code reduction} is negative
+     */
+    protected void reducePermits(int reduction) {
+        if (reduction < 0) throw new IllegalArgumentException();
+        sync.reducePermits(reduction);
+    }
+
+    /**
+     * Returns {@code true} if this semaphore has fairness set true.
+     *
+     * @return {@code true} if this semaphore has fairness set true
+     */
+    public boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire.
+     * The value is only an estimate because the number of threads may
+     * change dynamically while this method traverses internal data
+     * structures.  This method is designed for use in monitoring
+     * system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to acquire.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a best-effort
+     * estimate.  The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Returns a string identifying this semaphore, as well as its state.
+     * The state, in brackets, includes the String {@code "Permits ="}
+     * followed by the number of permits.
+     *
+     * @return a string identifying this semaphore, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Permits = " + sync.getPermits() + "]";
+    }
+}
diff --git a/android-35/java/util/concurrent/SubmissionPublisher.java b/android-35/java/util/concurrent/SubmissionPublisher.java
new file mode 100644
index 0000000..e3c2a60
--- /dev/null
+++ b/android-35/java/util/concurrent/SubmissionPublisher.java
@@ -0,0 +1,1524 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import static java.util.concurrent.Flow.Publisher;
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
+
+/**
+ * A {@link Flow.Publisher} that asynchronously issues submitted
+ * (non-null) items to current subscribers until it is closed.  Each
+ * current subscriber receives newly submitted items in the same order
+ * unless drops or exceptions are encountered.  Using a
+ * SubmissionPublisher allows item generators to act as compliant <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * Publishers relying on drop handling and/or blocking for flow
+ * control.
+ *
+ * <p>A SubmissionPublisher uses the {@link Executor} supplied in its
+ * constructor for delivery to subscribers. The best choice of
+ * Executor depends on expected usage. If the generator(s) of
+ * submitted items run in separate threads, and the number of
+ * subscribers can be estimated, consider using a {@link
+ * Executors#newFixedThreadPool}. Otherwise consider using the
+ * default, normally the {@link ForkJoinPool#commonPool}.
+ *
+ * <p>Buffering allows producers and consumers to transiently operate
+ * at different rates.  Each subscriber uses an independent buffer.
+ * Buffers are created upon first use and expanded as needed up to the
+ * given maximum. (The enforced capacity may be rounded up to the
+ * nearest power of two and/or bounded by the largest value supported
+ * by this implementation.)  Invocations of {@link
+ * Flow.Subscription#request(long) request} do not directly result in
+ * buffer expansion, but risk saturation if unfilled requests exceed
+ * the maximum capacity.  The default value of {@link
+ * Flow#defaultBufferSize()} may provide a useful starting point for
+ * choosing a capacity based on expected rates, resources, and usages.
+ *
+ * <p>A single SubmissionPublisher may be shared among multiple
+ * sources. Actions in a source thread prior to publishing an item or
+ * issuing a signal <a href="package-summary.html#MemoryVisibility">
+ * <i>happen-before</i></a> actions subsequent to the corresponding
+ * access by each subscriber. But reported estimates of lag and demand
+ * are designed for use in monitoring, not for synchronization
+ * control, and may reflect stale or inaccurate views of progress.
+ *
+ * <p>Publication methods support different policies about what to do
+ * when buffers are saturated. Method {@link #submit(Object) submit}
+ * blocks until resources are available. This is simplest, but least
+ * responsive.  The {@code offer} methods may drop items (either
+ * immediately or with bounded timeout), but provide an opportunity to
+ * interpose a handler and then retry.
+ *
+ * <p>If any Subscriber method throws an exception, its subscription
+ * is cancelled.  If a handler is supplied as a constructor argument,
+ * it is invoked before cancellation upon an exception in method
+ * {@link Flow.Subscriber#onNext onNext}, but exceptions in methods
+ * {@link Flow.Subscriber#onSubscribe onSubscribe},
+ * {@link Flow.Subscriber#onError(Throwable) onError} and
+ * {@link Flow.Subscriber#onComplete() onComplete} are not recorded or
+ * handled before cancellation.  If the supplied Executor throws
+ * {@link RejectedExecutionException} (or any other RuntimeException
+ * or Error) when attempting to execute a task, or a drop handler
+ * throws an exception when processing a dropped item, then the
+ * exception is rethrown. In these cases, not all subscribers will
+ * have been issued the published item. It is usually good practice to
+ * {@link #closeExceptionally closeExceptionally} in these cases.
+ *
+ * <p>Method {@link #consume(Consumer)} simplifies support for a
+ * common case in which the only action of a subscriber is to request
+ * and process all items using a supplied function.
+ *
+ * <p>This class may also serve as a convenient base for subclasses
+ * that generate items, and use the methods in this class to publish
+ * them.  For example here is a class that periodically publishes the
+ * items generated from a supplier. (In practice you might add methods
+ * to independently start and stop generation, to share Executors
+ * among publishers, and so on, or use a SubmissionPublisher as a
+ * component rather than a superclass.)
+ *
+ * <pre> {@code
+ * class PeriodicPublisher<T> extends SubmissionPublisher<T> {
+ *   final ScheduledFuture<?> periodicTask;
+ *   final ScheduledExecutorService scheduler;
+ *   PeriodicPublisher(Executor executor, int maxBufferCapacity,
+ *                     Supplier<? extends T> supplier,
+ *                     long period, TimeUnit unit) {
+ *     super(executor, maxBufferCapacity);
+ *     scheduler = new ScheduledThreadPoolExecutor(1);
+ *     periodicTask = scheduler.scheduleAtFixedRate(
+ *       () -> submit(supplier.get()), 0, period, unit);
+ *   }
+ *   public void close() {
+ *     periodicTask.cancel(false);
+ *     scheduler.shutdown();
+ *     super.close();
+ *   }
+ * }}</pre>
+ *
+ * <p>Here is an example of a {@link Flow.Processor} implementation.
+ * It uses single-step requests to its publisher for simplicity of
+ * illustration. A more adaptive version could monitor flow using the
+ * lag estimate returned from {@code submit}, along with other utility
+ * methods.
+ *
+ * <pre> {@code
+ * class TransformProcessor<S,T> extends SubmissionPublisher<T>
+ *   implements Flow.Processor<S,T> {
+ *   final Function<? super S, ? extends T> function;
+ *   Flow.Subscription subscription;
+ *   TransformProcessor(Executor executor, int maxBufferCapacity,
+ *                      Function<? super S, ? extends T> function) {
+ *     super(executor, maxBufferCapacity);
+ *     this.function = function;
+ *   }
+ *   public void onSubscribe(Flow.Subscription subscription) {
+ *     (this.subscription = subscription).request(1);
+ *   }
+ *   public void onNext(S item) {
+ *     subscription.request(1);
+ *     submit(function.apply(item));
+ *   }
+ *   public void onError(Throwable ex) { closeExceptionally(ex); }
+ *   public void onComplete() { close(); }
+ * }}</pre>
+ *
+ * @param <T> the published item type
+ * @author Doug Lea
+ * @since 9
+ */
+public class SubmissionPublisher<T> implements Publisher<T>,
+                                               AutoCloseable {
+    /*
+     * Most mechanics are handled by BufferedSubscription. This class
+     * mainly tracks subscribers and ensures sequentiality, by using
+     * locks across public methods, to ensure thread-safety in the
+     * presence of multiple sources and maintain acquire-release
+     * ordering around user operations. However, we also track whether
+     * there is only a single source, and if so streamline some buffer
+     * operations by avoiding some atomics.
+     */
+
+    /** The largest possible power of two array size. */
+    static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
+
+    /**
+     * Initial buffer capacity used when maxBufferCapacity is
+     * greater. Must be a power of two.
+     */
+    static final int INITIAL_CAPACITY = 32;
+
+    /** Round capacity to power of 2, at most limit. */
+    static final int roundCapacity(int cap) {
+        int n = cap - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n <= 0) ? 1 : // at least 1
+            (n >= BUFFER_CAPACITY_LIMIT) ? BUFFER_CAPACITY_LIMIT : n + 1;
+    }
+
+    // default Executor setup; nearly the same as CompletableFuture
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor ASYNC_POOL =
+        (ForkJoinPool.getCommonPoolParallelism() > 1) ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    private static final class ThreadPerTaskExecutor implements Executor {
+        ThreadPerTaskExecutor() {}      // prevent access constructor creation
+        public void execute(Runnable r) { new Thread(r).start(); }
+    }
+
+    /**
+     * Clients (BufferedSubscriptions) are maintained in a linked list
+     * (via their "next" fields). This works well for publish loops.
+     * It requires O(n) traversal to check for duplicate subscribers,
+     * but we expect that subscribing is much less common than
+     * publishing. Unsubscribing occurs only during traversal loops,
+     * when BufferedSubscription methods return negative values
+     * signifying that they have been closed.  To reduce
+     * head-of-line blocking, submit and offer methods first call
+     * BufferedSubscription.offer on each subscriber, and place
+     * saturated ones in retries list (using nextRetry field), and
+     * retry, possibly blocking or dropping.
+     */
+    BufferedSubscription<T> clients;
+
+    /** Lock for exclusion across multiple sources */
+    final ReentrantLock lock;
+    /** Run status, updated only within locks */
+    volatile boolean closed;
+    /** Set true on first call to subscribe, to initialize possible owner */
+    boolean subscribed;
+    /** The first caller thread to subscribe, or null if thread ever changed */
+    Thread owner;
+    /** If non-null, the exception in closeExceptionally */
+    volatile Throwable closedException;
+
+    // Parameters for constructing BufferedSubscriptions
+    final Executor executor;
+    final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+    final int maxBufferCapacity;
+
+    /**
+     * Creates a new SubmissionPublisher using the given Executor for
+     * async delivery to subscribers, with the given maximum buffer size
+     * for each subscriber, and, if non-null, the given handler invoked
+     * when any Subscriber throws an exception in method {@link
+     * Flow.Subscriber#onNext(Object) onNext}.
+     *
+     * @param executor the executor to use for async delivery,
+     * supporting creation of at least one independent thread
+     * @param maxBufferCapacity the maximum capacity for each
+     * subscriber's buffer (the enforced capacity may be rounded up to
+     * the nearest power of two and/or bounded by the largest value
+     * supported by this implementation; method {@link #getMaxBufferCapacity}
+     * returns the actual value)
+     * @param handler if non-null, procedure to invoke upon exception
+     * thrown in method {@code onNext}
+     * @throws NullPointerException if executor is null
+     * @throws IllegalArgumentException if maxBufferCapacity not
+     * positive
+     */
+    public SubmissionPublisher(Executor executor, int maxBufferCapacity,
+                               BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler) {
+        if (executor == null)
+            throw new NullPointerException();
+        if (maxBufferCapacity <= 0)
+            throw new IllegalArgumentException("capacity must be positive");
+        this.lock = new ReentrantLock();
+        this.executor = executor;
+        this.onNextHandler = handler;
+        this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
+    }
+
+    /**
+     * Creates a new SubmissionPublisher using the given Executor for
+     * async delivery to subscribers, with the given maximum buffer size
+     * for each subscriber, and no handler for Subscriber exceptions in
+     * method {@link Flow.Subscriber#onNext(Object) onNext}.
+     *
+     * @param executor the executor to use for async delivery,
+     * supporting creation of at least one independent thread
+     * @param maxBufferCapacity the maximum capacity for each
+     * subscriber's buffer (the enforced capacity may be rounded up to
+     * the nearest power of two and/or bounded by the largest value
+     * supported by this implementation; method {@link #getMaxBufferCapacity}
+     * returns the actual value)
+     * @throws NullPointerException if executor is null
+     * @throws IllegalArgumentException if maxBufferCapacity not
+     * positive
+     */
+    public SubmissionPublisher(Executor executor, int maxBufferCapacity) {
+        this(executor, maxBufferCapacity, null);
+    }
+
+    /**
+     * Creates a new SubmissionPublisher using the {@link
+     * ForkJoinPool#commonPool()} for async delivery to subscribers
+     * (unless it does not support a parallelism level of at least two,
+     * in which case, a new Thread is created to run each task), with
+     * maximum buffer capacity of {@link Flow#defaultBufferSize}, and no
+     * handler for Subscriber exceptions in method {@link
+     * Flow.Subscriber#onNext(Object) onNext}.
+     */
+    public SubmissionPublisher() {
+        this(ASYNC_POOL, Flow.defaultBufferSize(), null);
+    }
+
+    /**
+     * Adds the given Subscriber unless already subscribed.  If already
+     * subscribed, the Subscriber's {@link
+     * Flow.Subscriber#onError(Throwable) onError} method is invoked on
+     * the existing subscription with an {@link IllegalStateException}.
+     * Otherwise, upon success, the Subscriber's {@link
+     * Flow.Subscriber#onSubscribe onSubscribe} method is invoked
+     * asynchronously with a new {@link Flow.Subscription}.  If {@link
+     * Flow.Subscriber#onSubscribe onSubscribe} throws an exception, the
+     * subscription is cancelled. Otherwise, if this SubmissionPublisher
+     * was closed exceptionally, then the subscriber's {@link
+     * Flow.Subscriber#onError onError} method is invoked with the
+     * corresponding exception, or if closed without exception, the
+     * subscriber's {@link Flow.Subscriber#onComplete() onComplete}
+     * method is invoked.  Subscribers may enable receiving items by
+     * invoking the {@link Flow.Subscription#request(long) request}
+     * method of the new Subscription, and may unsubscribe by invoking
+     * its {@link Flow.Subscription#cancel() cancel} method.
+     *
+     * @param subscriber the subscriber
+     * @throws NullPointerException if subscriber is null
+     */
+    public void subscribe(Subscriber<? super T> subscriber) {
+        if (subscriber == null) throw new NullPointerException();
+        ReentrantLock lock = this.lock;
+        int max = maxBufferCapacity; // allocate initial array
+        Object[] array = new Object[max < INITIAL_CAPACITY ?
+                                    max : INITIAL_CAPACITY];
+        BufferedSubscription<T> subscription =
+            new BufferedSubscription<T>(subscriber, executor, onNextHandler,
+                                        array, max);
+        lock.lock();
+        try {
+            if (!subscribed) {
+                subscribed = true;
+                owner = Thread.currentThread();
+            }
+            for (BufferedSubscription<T> b = clients, pred = null;;) {
+                if (b == null) {
+                    Throwable ex;
+                    subscription.onSubscribe();
+                    if ((ex = closedException) != null)
+                        subscription.onError(ex);
+                    else if (closed)
+                        subscription.onComplete();
+                    else if (pred == null)
+                        clients = subscription;
+                    else
+                        pred.next = subscription;
+                    break;
+                }
+                BufferedSubscription<T> next = b.next;
+                if (b.isClosed()) {   // remove
+                    b.next = null;    // detach
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else if (subscriber.equals(b.subscriber)) {
+                    b.onError(new IllegalStateException("Duplicate subscribe"));
+                    break;
+                }
+                else
+                    pred = b;
+                b = next;
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Common implementation for all three forms of submit and offer.
+     * Acts as submit if nanos == Long.MAX_VALUE, else offer.
+     */
+    private int doOffer(T item, long nanos,
+                        BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        if (item == null) throw new NullPointerException();
+        int lag = 0;
+        boolean complete, unowned;
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Thread t = Thread.currentThread(), o;
+            BufferedSubscription<T> b = clients;
+            if ((unowned = ((o = owner) != t)) && o != null)
+                owner = null;                     // disable bias
+            if (b == null)
+                complete = closed;
+            else {
+                complete = false;
+                boolean cleanMe = false;
+                BufferedSubscription<T> retries = null, rtail = null, next;
+                do {
+                    next = b.next;
+                    int stat = b.offer(item, unowned);
+                    if (stat == 0) {              // saturated; add to retry list
+                        b.nextRetry = null;       // avoid garbage on exceptions
+                        if (rtail == null)
+                            retries = b;
+                        else
+                            rtail.nextRetry = b;
+                        rtail = b;
+                    }
+                    else if (stat < 0)            // closed
+                        cleanMe = true;           // remove later
+                    else if (stat > lag)
+                        lag = stat;
+                } while ((b = next) != null);
+
+                if (retries != null || cleanMe)
+                    lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
+            }
+        } finally {
+            lock.unlock();
+        }
+        if (complete)
+            throw new IllegalStateException("Closed");
+        else
+            return lag;
+    }
+
+    /**
+     * Helps, (timed) waits for, and/or drops buffers on list; returns
+     * lag or negative drops (for use in offer).
+     */
+    private int retryOffer(T item, long nanos,
+                           BiPredicate<Subscriber<? super T>, ? super T> onDrop,
+                           BufferedSubscription<T> retries, int lag,
+                           boolean cleanMe) {
+        for (BufferedSubscription<T> r = retries; r != null;) {
+            BufferedSubscription<T> nextRetry = r.nextRetry;
+            r.nextRetry = null;
+            if (nanos > 0L)
+                r.awaitSpace(nanos);
+            int stat = r.retryOffer(item);
+            if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
+                stat = r.retryOffer(item);
+            if (stat == 0)
+                lag = (lag >= 0) ? -1 : lag - 1;
+            else if (stat < 0)
+                cleanMe = true;
+            else if (lag >= 0 && stat > lag)
+                lag = stat;
+            r = nextRetry;
+        }
+        if (cleanMe)
+            cleanAndCount();
+        return lag;
+    }
+
+    /**
+     * Returns current list count after removing closed subscribers.
+     * Call only while holding lock.  Used mainly by retryOffer for
+     * cleanup.
+     */
+    private int cleanAndCount() {
+        int count = 0;
+        BufferedSubscription<T> pred = null, next;
+        for (BufferedSubscription<T> b = clients; b != null; b = next) {
+            next = b.next;
+            if (b.isClosed()) {
+                b.next = null;
+                if (pred == null)
+                    clients = next;
+                else
+                    pred.next = next;
+            }
+            else {
+                pred = b;
+                ++count;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Publishes the given item to each current subscriber by
+     * asynchronously invoking its {@link Flow.Subscriber#onNext(Object)
+     * onNext} method, blocking uninterruptibly while resources for any
+     * subscriber are unavailable. This method returns an estimate of
+     * the maximum lag (number of items submitted but not yet consumed)
+     * among all current subscribers. This value is at least one
+     * (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers,
+     * then this exception is rethrown, in which case not all
+     * subscribers will have been issued this item.
+     *
+     * @param item the (non-null) item to publish
+     * @return the estimated maximum lag among subscribers
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int submit(T item) {
+        return doOffer(item, Long.MAX_VALUE, null);
+    }
+
+    /**
+     * Publishes the given item, if possible, to each current subscriber
+     * by asynchronously invoking its {@link
+     * Flow.Subscriber#onNext(Object) onNext} method. The item may be
+     * dropped by one or more subscribers if resource limits are
+     * exceeded, in which case the given handler (if non-null) is
+     * invoked, and if it returns true, retried once.  Other calls to
+     * methods in this class by other threads are blocked while the
+     * handler is invoked.  Unless recovery is assured, options are
+     * usually limited to logging the error and/or issuing an {@link
+     * Flow.Subscriber#onError(Throwable) onError} signal to the
+     * subscriber.
+     *
+     * <p>This method returns a status indicator: If negative, it
+     * represents the (negative) number of drops (failed attempts to
+     * issue the item to a subscriber). Otherwise it is an estimate of
+     * the maximum lag (number of items submitted but not yet
+     * consumed) among all current subscribers. This value is at least
+     * one (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers, or
+     * the drop handler throws an exception when processing a dropped
+     * item, then this exception is rethrown.
+     *
+     * @param item the (non-null) item to publish
+     * @param onDrop if non-null, the handler invoked upon a drop to a
+     * subscriber, with arguments of the subscriber and item; if it
+     * returns true, an offer is re-attempted (once)
+     * @return if negative, the (negative) number of drops; otherwise
+     * an estimate of maximum lag
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int offer(T item,
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        return doOffer(item, 0L, onDrop);
+    }
+
+    /**
+     * Publishes the given item, if possible, to each current subscriber
+     * by asynchronously invoking its {@link
+     * Flow.Subscriber#onNext(Object) onNext} method, blocking while
+     * resources for any subscription are unavailable, up to the
+     * specified timeout or until the caller thread is interrupted, at
+     * which point the given handler (if non-null) is invoked, and if it
+     * returns true, retried once. (The drop handler may distinguish
+     * timeouts from interrupts by checking whether the current thread
+     * is interrupted.)  Other calls to methods in this class by other
+     * threads are blocked while the handler is invoked.  Unless
+     * recovery is assured, options are usually limited to logging the
+     * error and/or issuing an {@link Flow.Subscriber#onError(Throwable)
+     * onError} signal to the subscriber.
+     *
+     * <p>This method returns a status indicator: If negative, it
+     * represents the (negative) number of drops (failed attempts to
+     * issue the item to a subscriber). Otherwise it is an estimate of
+     * the maximum lag (number of items submitted but not yet
+     * consumed) among all current subscribers. This value is at least
+     * one (accounting for this submitted item) if there are any
+     * subscribers, else zero.
+     *
+     * <p>If the Executor for this publisher throws a
+     * RejectedExecutionException (or any other RuntimeException or
+     * Error) when attempting to asynchronously notify subscribers, or
+     * the drop handler throws an exception when processing a dropped
+     * item, then this exception is rethrown.
+     *
+     * @param item the (non-null) item to publish
+     * @param timeout how long to wait for resources for any subscriber
+     * before giving up, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     * {@code timeout} parameter
+     * @param onDrop if non-null, the handler invoked upon a drop to a
+     * subscriber, with arguments of the subscriber and item; if it
+     * returns true, an offer is re-attempted (once)
+     * @return if negative, the (negative) number of drops; otherwise
+     * an estimate of maximum lag
+     * @throws IllegalStateException if closed
+     * @throws NullPointerException if item is null
+     * @throws RejectedExecutionException if thrown by Executor
+     */
+    public int offer(T item, long timeout, TimeUnit unit,
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        long nanos = unit.toNanos(timeout);
+        // distinguishes from untimed (only wrt interrupt policy)
+        if (nanos == Long.MAX_VALUE) --nanos;
+        return doOffer(item, nanos, onDrop);
+    }
+
+    /**
+     * Unless already closed, issues {@link
+     * Flow.Subscriber#onComplete() onComplete} signals to current
+     * subscribers, and disallows subsequent attempts to publish.
+     * Upon return, this method does <em>NOT</em> guarantee that all
+     * subscribers have yet completed.
+     */
+    public void close() {
+        ReentrantLock lock = this.lock;
+        if (!closed) {
+            BufferedSubscription<T> b;
+            lock.lock();
+            try {
+                // no need to re-check closed here
+                b = clients;
+                clients = null;
+                owner = null;
+                closed = true;
+            } finally {
+                lock.unlock();
+            }
+            while (b != null) {
+                BufferedSubscription<T> next = b.next;
+                b.next = null;
+                b.onComplete();
+                b = next;
+            }
+        }
+    }
+
+    /**
+     * Unless already closed, issues {@link
+     * Flow.Subscriber#onError(Throwable) onError} signals to current
+     * subscribers with the given error, and disallows subsequent
+     * attempts to publish.  Future subscribers also receive the given
+     * error. Upon return, this method does <em>NOT</em> guarantee
+     * that all subscribers have yet completed.
+     *
+     * @param error the {@code onError} argument sent to subscribers
+     * @throws NullPointerException if error is null
+     */
+    public void closeExceptionally(Throwable error) {
+        if (error == null)
+            throw new NullPointerException();
+        ReentrantLock lock = this.lock;
+        if (!closed) {
+            BufferedSubscription<T> b;
+            lock.lock();
+            try {
+                b = clients;
+                if (!closed) {  // don't clobber racing close
+                    closedException = error;
+                    clients = null;
+                    owner = null;
+                    closed = true;
+                }
+            } finally {
+                lock.unlock();
+            }
+            while (b != null) {
+                BufferedSubscription<T> next = b.next;
+                b.next = null;
+                b.onError(error);
+                b = next;
+            }
+        }
+    }
+
+    /**
+     * Returns true if this publisher is not accepting submissions.
+     *
+     * @return true if closed
+     */
+    public boolean isClosed() {
+        return closed;
+    }
+
+    /**
+     * Returns the exception associated with {@link
+     * #closeExceptionally(Throwable) closeExceptionally}, or null if
+     * not closed or if closed normally.
+     *
+     * @return the exception, or null if none
+     */
+    public Throwable getClosedException() {
+        return closedException;
+    }
+
+    /**
+     * Returns true if this publisher has any subscribers.
+     *
+     * @return true if this publisher has any subscribers
+     */
+    public boolean hasSubscribers() {
+        boolean nonEmpty = false;
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (BufferedSubscription<T> b = clients; b != null;) {
+                BufferedSubscription<T> next = b.next;
+                if (b.isClosed()) {
+                    b.next = null;
+                    b = clients = next;
+                }
+                else {
+                    nonEmpty = true;
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        return nonEmpty;
+    }
+
+    /**
+     * Returns the number of current subscribers.
+     *
+     * @return the number of current subscribers
+     */
+    public int getNumberOfSubscribers() {
+        int n;
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            n = cleanAndCount();
+        } finally {
+            lock.unlock();
+        }
+        return n;
+    }
+
+    /**
+     * Returns the Executor used for asynchronous delivery.
+     *
+     * @return the Executor used for asynchronous delivery
+     */
+    public Executor getExecutor() {
+        return executor;
+    }
+
+    /**
+     * Returns the maximum per-subscriber buffer capacity.
+     *
+     * @return the maximum per-subscriber buffer capacity
+     */
+    public int getMaxBufferCapacity() {
+        return maxBufferCapacity;
+    }
+
+    /**
+     * Returns a list of current subscribers for monitoring and
+     * tracking purposes, not for invoking {@link Flow.Subscriber}
+     * methods on the subscribers.
+     *
+     * @return list of current subscribers
+     */
+    public List<Subscriber<? super T>> getSubscribers() {
+        ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                next = b.next;
+                if (b.isClosed()) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    subs.add(b.subscriber);
+                    pred = b;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        return subs;
+    }
+
+    /**
+     * Returns true if the given Subscriber is currently subscribed.
+     *
+     * @param subscriber the subscriber
+     * @return true if currently subscribed
+     * @throws NullPointerException if subscriber is null
+     */
+    public boolean isSubscribed(Subscriber<? super T> subscriber) {
+        if (subscriber == null) throw new NullPointerException();
+        boolean subscribed = false;
+        ReentrantLock lock = this.lock;
+        if (!closed) {
+            lock.lock();
+            try {
+                BufferedSubscription<T> pred = null, next;
+                for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                    next = b.next;
+                    if (b.isClosed()) {
+                        b.next = null;
+                        if (pred == null)
+                            clients = next;
+                        else
+                            pred.next = next;
+                    }
+                    else if (subscribed = subscriber.equals(b.subscriber))
+                        break;
+                    else
+                        pred = b;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return subscribed;
+    }
+
+    /**
+     * Returns an estimate of the minimum number of items requested
+     * (via {@link Flow.Subscription#request(long) request}) but not
+     * yet produced, among all current subscribers.
+     *
+     * @return the estimate, or zero if no subscribers
+     */
+    public long estimateMinimumDemand() {
+        long min = Long.MAX_VALUE;
+        boolean nonEmpty = false;
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                int n; long d;
+                next = b.next;
+                if ((n = b.estimateLag()) < 0) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    if ((d = b.demand - n) < min)
+                        min = d;
+                    nonEmpty = true;
+                    pred = b;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        return nonEmpty ? min : 0;
+    }
+
+    /**
+     * Returns an estimate of the maximum number of items produced but
+     * not yet consumed among all current subscribers.
+     *
+     * @return the estimate
+     */
+    public int estimateMaximumLag() {
+        int max = 0;
+        ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            BufferedSubscription<T> pred = null, next;
+            for (BufferedSubscription<T> b = clients; b != null; b = next) {
+                int n;
+                next = b.next;
+                if ((n = b.estimateLag()) < 0) {
+                    b.next = null;
+                    if (pred == null)
+                        clients = next;
+                    else
+                        pred.next = next;
+                }
+                else {
+                    if (n > max)
+                        max = n;
+                    pred = b;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        return max;
+    }
+
+    /**
+     * Processes all published items using the given Consumer function.
+     * Returns a CompletableFuture that is completed normally when this
+     * publisher signals {@link Flow.Subscriber#onComplete()
+     * onComplete}, or completed exceptionally upon any error, or an
+     * exception is thrown by the Consumer, or the returned
+     * CompletableFuture is cancelled, in which case no further items
+     * are processed.
+     *
+     * @param consumer the function applied to each onNext item
+     * @return a CompletableFuture that is completed normally
+     * when the publisher signals onComplete, and exceptionally
+     * upon any error or cancellation
+     * @throws NullPointerException if consumer is null
+     */
+    public CompletableFuture<Void> consume(Consumer<? super T> consumer) {
+        if (consumer == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> status = new CompletableFuture<>();
+        subscribe(new ConsumerSubscriber<T>(status, consumer));
+        return status;
+    }
+
+    /** Subscriber for method consume */
+    static final class ConsumerSubscriber<T> implements Subscriber<T> {
+        final CompletableFuture<Void> status;
+        final Consumer<? super T> consumer;
+        Subscription subscription;
+        ConsumerSubscriber(CompletableFuture<Void> status,
+                           Consumer<? super T> consumer) {
+            this.status = status; this.consumer = consumer;
+        }
+        public final void onSubscribe(Subscription subscription) {
+            this.subscription = subscription;
+            status.whenComplete((v, e) -> subscription.cancel());
+            if (!status.isDone())
+                subscription.request(Long.MAX_VALUE);
+        }
+        public final void onError(Throwable ex) {
+            status.completeExceptionally(ex);
+        }
+        public final void onComplete() {
+            status.complete(null);
+        }
+        public final void onNext(T item) {
+            try {
+                consumer.accept(item);
+            } catch (Throwable ex) {
+                subscription.cancel();
+                status.completeExceptionally(ex);
+            }
+        }
+    }
+
+    /**
+     * A task for consuming buffer items and signals, created and
+     * executed whenever they become available. A task consumes as
+     * many items/signals as possible before terminating, at which
+     * point another task is created when needed. The dual Runnable
+     * and ForkJoinTask declaration saves overhead when executed by
+     * ForkJoinPools, without impacting other kinds of Executors.
+     */
+    @SuppressWarnings("serial")
+    static final class ConsumerTask<T> extends ForkJoinTask<Void>
+        implements Runnable, CompletableFuture.AsynchronousCompletionTask {
+        final BufferedSubscription<T> consumer;
+        ConsumerTask(BufferedSubscription<T> consumer) {
+            this.consumer = consumer;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { consumer.consume(); return false; }
+        public final void run() { consumer.consume(); }
+    }
+
+    /**
+     * A resizable array-based ring buffer with integrated control to
+     * start a consumer task whenever items are available.  The buffer
+     * algorithm is specialized for the case of at most one concurrent
+     * producer and consumer, and power of two buffer sizes. It relies
+     * primarily on atomic operations (CAS or getAndSet) at the next
+     * array slot to put or take an element, at the "tail" and "head"
+     * indices written only by the producer and consumer respectively.
+     *
+     * We ensure internally that there is at most one active consumer
+     * task at any given time. The publisher guarantees a single
+     * producer via its lock. Sync among producers and consumers
+     * relies on volatile fields "ctl", "demand", and "waiting" (along
+     * with element access). Other variables are accessed in plain
+     * mode, relying on outer ordering and exclusion, and/or enclosing
+     * them within other volatile accesses. Some atomic operations are
+     * avoided by tracking single threaded ownership by producers (in
+     * the style of biased locking).
+     *
+     * Execution control and protocol state are managed using field
+     * "ctl".  Methods to subscribe, close, request, and cancel set
+     * ctl bits (mostly using atomic boolean method getAndBitwiseOr),
+     * and ensure that a task is running. (The corresponding consumer
+     * side actions are in method consume.)  To avoid starting a new
+     * task on each action, ctl also includes a keep-alive bit
+     * (ACTIVE) that is refreshed if needed on producer actions.
+     * (Maintaining agreement about keep-alives requires most atomic
+     * updates to be full SC/Volatile strength, which is still much
+     * cheaper than using one task per item.)  Error signals
+     * additionally null out items and/or fields to reduce termination
+     * latency.  The cancel() method is supported by treating as ERROR
+     * but suppressing onError signal.
+     *
+     * Support for blocking also exploits the fact that there is only
+     * one possible waiter. ManagedBlocker-compatible control fields
+     * are placed in this class itself rather than in wait-nodes.
+     * Blocking control relies on the "waiting" and "waiter"
+     * fields. Producers set them before trying to block. Signalling
+     * unparks and clears fields. If the producer and/or consumer are
+     * using a ForkJoinPool, the producer attempts to help run
+     * consumer tasks via ForkJoinPool.helpAsyncBlocker before
+     * blocking.
+     *
+     * Usages of this class may encounter any of several forms of
+     * memory contention. We try to ameliorate across them without
+     * unduly impacting footprints in low-contention usages where it
+     * isn't needed. Buffer arrays start out small and grow only as
+     * needed.  The class uses @Contended and heuristic field
+     * declaration ordering to reduce false-sharing memory contention
+     * across instances of BufferedSubscription (as in, multiple
+     * subscribers per publisher).  We additionally segregate some
+     * fields that would otherwise nearly always encounter cache line
+     * contention among producers and consumers. To reduce contention
+     * across time (vs space), consumers only periodically update
+     * other fields (see method takeItems), at the expense of possibly
+     * staler reporting of lags and demand (bounded at 12.5% == 1/8
+     * capacity) and possibly more atomic operations.
+     *
+     * Other forms of imbalance and slowdowns can occur during startup
+     * when producer and consumer methods are compiled and/or memory
+     * is allocated at different rates.  This is ameliorated by
+     * artificially subdividing some consumer methods, including
+     * isolation of all subscriber callbacks.  This code also includes
+     * typical power-of-two array screening idioms to avoid compilers
+     * generating traps, along with the usual SSA-based inline
+     * assignment coding style. Also, all methods and fields have
+     * default visibility to simplify usage by callers.
+     */
+    @SuppressWarnings("serial")
+    @jdk.internal.vm.annotation.Contended
+    static final class BufferedSubscription<T>
+        implements Subscription, ForkJoinPool.ManagedBlocker {
+        long timeout;                      // Long.MAX_VALUE if untimed wait
+        int head;                          // next position to take
+        int tail;                          // next position to put
+        final int maxCapacity;             // max buffer size
+        volatile int ctl;                  // atomic run state flags
+        Object[] array;                    // buffer
+        final Subscriber<? super T> subscriber;
+        final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+        Executor executor;                 // null on error
+        Thread waiter;                     // blocked producer thread
+        Throwable pendingError;            // holds until onError issued
+        BufferedSubscription<T> next;      // used only by publisher
+        BufferedSubscription<T> nextRetry; // used only by publisher
+
+        @jdk.internal.vm.annotation.Contended("c") // segregate
+        volatile long demand;              // # unfilled requests
+        @jdk.internal.vm.annotation.Contended("c")
+        volatile int waiting;              // nonzero if producer blocked
+
+        // ctl bit values
+        static final int CLOSED   = 0x01;  // if set, other bits ignored
+        static final int ACTIVE   = 0x02;  // keep-alive for consumer task
+        static final int REQS     = 0x04;  // (possibly) nonzero demand
+        static final int ERROR    = 0x08;  // issues onError when noticed
+        static final int COMPLETE = 0x10;  // issues onComplete when done
+        static final int RUN      = 0x20;  // task is or will be running
+        static final int OPEN     = 0x40;  // true after subscribe
+
+        static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
+
+        BufferedSubscription(Subscriber<? super T> subscriber,
+                             Executor executor,
+                             BiConsumer<? super Subscriber<? super T>,
+                             ? super Throwable> onNextHandler,
+                             Object[] array,
+                             int maxBufferCapacity) {
+            this.subscriber = subscriber;
+            this.executor = executor;
+            this.onNextHandler = onNextHandler;
+            this.array = array;
+            this.maxCapacity = maxBufferCapacity;
+        }
+
+        // Wrappers for some VarHandle methods
+
+        final boolean weakCasCtl(int cmp, int val) {
+            return CTL.weakCompareAndSet(this, cmp, val);
+        }
+
+        final int getAndBitwiseOrCtl(int bits) {
+            return (int)CTL.getAndBitwiseOr(this, bits);
+        }
+
+        final long subtractDemand(int k) {
+            long n = (long)(-k);
+            return n + (long)DEMAND.getAndAdd(this, n);
+        }
+
+        final boolean casDemand(long cmp, long val) {
+            return DEMAND.compareAndSet(this, cmp, val);
+        }
+
+        // Utilities used by SubmissionPublisher
+
+        /**
+         * Returns true if closed (consumer task may still be running).
+         */
+        final boolean isClosed() {
+            return (ctl & CLOSED) != 0;
+        }
+
+        /**
+         * Returns estimated number of buffered items, or negative if
+         * closed.
+         */
+        final int estimateLag() {
+            int c = ctl, n = tail - head;
+            return ((c & CLOSED) != 0) ? -1 : (n < 0) ? 0 : n;
+        }
+
+        // Methods for submitting items
+
+        /**
+         * Tries to add item and start consumer task if necessary.
+         * @return negative if closed, 0 if saturated, else estimated lag
+         */
+        final int offer(T item, boolean unowned) {
+            Object[] a;
+            int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
+            int t = tail, i = t & (cap - 1), n = t + 1 - head;
+            if (cap > 0) {
+                boolean added;
+                if (n >= cap && cap < maxCapacity) // resize
+                    added = growAndOffer(item, a, t);
+                else if (n >= cap || unowned)      // need volatile CAS
+                    added = QA.compareAndSet(a, i, null, item);
+                else {                             // can use release mode
+                    QA.setRelease(a, i, item);
+                    added = true;
+                }
+                if (added) {
+                    tail = t + 1;
+                    stat = n;
+                }
+            }
+            return startOnOffer(stat);
+        }
+
+        /**
+         * Tries to expand buffer and add item, returning true on
+         * success. Currently fails only if out of memory.
+         */
+        final boolean growAndOffer(T item, Object[] a, int t) {
+            int cap = 0, newCap = 0;
+            Object[] newArray = null;
+            if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
+                try {
+                    newArray = new Object[newCap];
+                } catch (OutOfMemoryError ex) {
+                }
+            }
+            if (newArray == null)
+                return false;
+            else {                                // take and move items
+                int newMask = newCap - 1;
+                newArray[t-- & newMask] = item;
+                for (int mask = cap - 1, k = mask; k >= 0; --k) {
+                    Object x = QA.getAndSet(a, t & mask, null);
+                    if (x == null)
+                        break;                    // already consumed
+                    else
+                        newArray[t-- & newMask] = x;
+                }
+                array = newArray;
+                VarHandle.releaseFence();         // release array and slots
+                return true;
+            }
+        }
+
+        /**
+         * Version of offer for retries (no resize or bias)
+         */
+        final int retryOffer(T item) {
+            Object[] a;
+            int stat = 0, t = tail, h = head, cap;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                QA.compareAndSet(a, (cap - 1) & t, null, item))
+                stat = (tail = t + 1) - h;
+            return startOnOffer(stat);
+        }
+
+        /**
+         * Tries to start consumer task after offer.
+         * @return negative if now closed, else argument
+         */
+        final int startOnOffer(int stat) {
+            int c; // start or keep alive if requests exist and not active
+            if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
+                ((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
+                tryStart();
+            else if ((c & CLOSED) != 0)
+                stat = -1;
+            return stat;
+        }
+
+        /**
+         * Tries to start consumer task. Sets error state on failure.
+         */
+        final void tryStart() {
+            try {
+                Executor e;
+                ConsumerTask<T> task = new ConsumerTask<T>(this);
+                if ((e = executor) != null)   // skip if disabled on error
+                    e.execute(task);
+            } catch (RuntimeException | Error ex) {
+                getAndBitwiseOrCtl(ERROR | CLOSED);
+                throw ex;
+            }
+        }
+
+        // Signals to consumer tasks
+
+        /**
+         * Sets the given control bits, starting task if not running or closed.
+         * @param bits state bits, assumed to include RUN but not CLOSED
+         */
+        final void startOnSignal(int bits) {
+            if ((ctl & bits) != bits &&
+                (getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
+                tryStart();
+        }
+
+        final void onSubscribe() {
+            startOnSignal(RUN | ACTIVE);
+        }
+
+        final void onComplete() {
+            startOnSignal(RUN | ACTIVE | COMPLETE);
+        }
+
+        final void onError(Throwable ex) {
+            int c; Object[] a;      // to null out buffer on async error
+            if (ex != null)
+                pendingError = ex;  // races are OK
+            if (((c = getAndBitwiseOrCtl(ERROR | RUN | ACTIVE)) & CLOSED) == 0) {
+                if ((c & RUN) == 0)
+                    tryStart();
+                else if ((a = array) != null)
+                    Arrays.fill(a, null);
+            }
+        }
+
+        public final void cancel() {
+            onError(null);
+        }
+
+        public final void request(long n) {
+            if (n > 0L) {
+                for (;;) {
+                    long p = demand, d = p + n;  // saturate
+                    if (casDemand(p, d < p ? Long.MAX_VALUE : d))
+                        break;
+                }
+                startOnSignal(RUN | ACTIVE | REQS);
+            }
+            else
+                onError(new IllegalArgumentException(
+                            "non-positive subscription request"));
+        }
+
+        // Consumer task actions
+
+        /**
+         * Consumer loop, called from ConsumerTask, or indirectly when
+         * helping during submit.
+         */
+        final void consume() {
+            Subscriber<? super T> s;
+            if ((s = subscriber) != null) {          // hoist checks
+                subscribeOnOpen(s);
+                long d = demand;
+                for (int h = head, t = tail;;) {
+                    int c, taken; boolean empty;
+                    if (((c = ctl) & ERROR) != 0) {
+                        closeOnError(s, null);
+                        break;
+                    }
+                    else if ((taken = takeItems(s, d, h)) > 0) {
+                        head = h += taken;
+                        d = subtractDemand(taken);
+                    }
+                    else if ((d = demand) == 0L && (c & REQS) != 0)
+                        weakCasCtl(c, c & ~REQS);    // exhausted demand
+                    else if (d != 0L && (c & REQS) == 0)
+                        weakCasCtl(c, c | REQS);     // new demand
+                    else if (t == (t = tail)) {      // stability check
+                        if ((empty = (t == h)) && (c & COMPLETE) != 0) {
+                            closeOnComplete(s);      // end of stream
+                            break;
+                        }
+                        else if (empty || d == 0L) {
+                            int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
+                            if (weakCasCtl(c, c & ~bit) && bit == RUN)
+                                break;               // un-keep-alive or exit
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Consumes some items until unavailable or bound or error.
+         *
+         * @param s subscriber
+         * @param d current demand
+         * @param h current head
+         * @return number taken
+         */
+        final int takeItems(Subscriber<? super T> s, long d, int h) {
+            Object[] a;
+            int k = 0, cap;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
+                int n = (d < (long)b) ? (int)d : b;
+                for (; k < n; ++h, ++k) {
+                    Object x = QA.getAndSet(a, h & m, null);
+                    if (waiting != 0)
+                        signalWaiter();
+                    if (x == null)
+                        break;
+                    else if (!consumeNext(s, x))
+                        break;
+                }
+            }
+            return k;
+        }
+
+        final boolean consumeNext(Subscriber<? super T> s, Object x) {
+            try {
+                @SuppressWarnings("unchecked") T y = (T) x;
+                if (s != null)
+                    s.onNext(y);
+                return true;
+            } catch (Throwable ex) {
+                handleOnNext(s, ex);
+                return false;
+            }
+        }
+
+        /**
+         * Processes exception in Subscriber.onNext.
+         */
+        final void handleOnNext(Subscriber<? super T> s, Throwable ex) {
+            BiConsumer<? super Subscriber<? super T>, ? super Throwable> h;
+            try {
+                if ((h = onNextHandler) != null)
+                    h.accept(s, ex);
+            } catch (Throwable ignore) {
+            }
+            closeOnError(s, ex);
+        }
+
+        /**
+         * Issues subscriber.onSubscribe if this is first signal.
+         */
+        final void subscribeOnOpen(Subscriber<? super T> s) {
+            if ((ctl & OPEN) == 0 && (getAndBitwiseOrCtl(OPEN) & OPEN) == 0)
+                consumeSubscribe(s);
+        }
+
+        final void consumeSubscribe(Subscriber<? super T> s) {
+            try {
+                if (s != null) // ignore if disabled
+                    s.onSubscribe(this);
+            } catch (Throwable ex) {
+                closeOnError(s, ex);
+            }
+        }
+
+        /**
+         * Issues subscriber.onComplete unless already closed.
+         */
+        final void closeOnComplete(Subscriber<? super T> s) {
+            if ((getAndBitwiseOrCtl(CLOSED) & CLOSED) == 0)
+                consumeComplete(s);
+        }
+
+        final void consumeComplete(Subscriber<? super T> s) {
+            try {
+                if (s != null)
+                    s.onComplete();
+            } catch (Throwable ignore) {
+            }
+        }
+
+        /**
+         * Issues subscriber.onError, and unblocks producer if needed.
+         */
+        final void closeOnError(Subscriber<? super T> s, Throwable ex) {
+            if ((getAndBitwiseOrCtl(ERROR | CLOSED) & CLOSED) == 0) {
+                if (ex == null)
+                    ex = pendingError;
+                pendingError = null;  // detach
+                executor = null;      // suppress racing start calls
+                signalWaiter();
+                consumeError(s, ex);
+            }
+        }
+
+        final void consumeError(Subscriber<? super T> s, Throwable ex) {
+            try {
+                if (ex != null && s != null)
+                    s.onError(ex);
+            } catch (Throwable ignore) {
+            }
+        }
+
+        // Blocking support
+
+        /**
+         * Unblocks waiting producer.
+         */
+        final void signalWaiter() {
+            Thread w;
+            waiting = 0;
+            if ((w = waiter) != null)
+                LockSupport.unpark(w);
+        }
+
+        /**
+         * Returns true if closed or space available.
+         * For ManagedBlocker.
+         */
+        public final boolean isReleasable() {
+            Object[] a; int cap;
+            return ((ctl & CLOSED) != 0 ||
+                    ((a = array) != null && (cap = a.length) > 0 &&
+                     QA.getAcquire(a, (cap - 1) & tail) == null));
+        }
+
+        /**
+         * Helps or blocks until timeout, closed, or space available.
+         */
+        final void awaitSpace(long nanos) {
+            if (!isReleasable()) {
+                ForkJoinPool.helpAsyncBlocker(executor, this);
+                if (!isReleasable()) {
+                    timeout = nanos;
+                    try {
+                        ForkJoinPool.managedBlock(this);
+                    } catch (InterruptedException ie) {
+                        timeout = INTERRUPTED;
+                    }
+                    if (timeout == INTERRUPTED)
+                        Thread.currentThread().interrupt();
+                }
+            }
+        }
+
+        /**
+         * Blocks until closed, space available or timeout.
+         * For ManagedBlocker.
+         */
+        public final boolean block() {
+            long nanos = timeout;
+            boolean timed = (nanos < Long.MAX_VALUE);
+            long deadline = timed ? System.nanoTime() + nanos : 0L;
+            while (!isReleasable()) {
+                if (Thread.interrupted()) {
+                    timeout = INTERRUPTED;
+                    if (timed)
+                        break;
+                }
+                else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
+                    break;
+                else if (waiter == null)
+                    waiter = Thread.currentThread();
+                else if (waiting == 0)
+                    waiting = 1;
+                else if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            waiter = null;
+            waiting = 0;
+            return true;
+        }
+
+        // VarHandle mechanics
+        static final VarHandle CTL;
+        static final VarHandle DEMAND;
+        static final VarHandle QA;
+
+        static {
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
+                                      int.class);
+                DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
+                                         long.class);
+                QA = MethodHandles.arrayElementVarHandle(Object[].class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+
+            // Reduce the risk of rare disastrous classloading in first call to
+            // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+            Class<?> ensureLoaded = LockSupport.class;
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/SynchronousQueue.java b/android-35/java/util/concurrent/SynchronousQueue.java
new file mode 100644
index 0000000..926897c
--- /dev/null
+++ b/android-35/java/util/concurrent/SynchronousQueue.java
@@ -0,0 +1,1168 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, 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/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A {@linkplain BlockingQueue blocking queue} in which each insert
+ * operation must wait for a corresponding remove operation by another
+ * thread, and vice versa.  A synchronous queue does not have any
+ * internal capacity, not even a capacity of one.  You cannot
+ * {@code peek} at a synchronous queue because an element is only
+ * present when you try to remove it; you cannot insert an element
+ * (using any method) unless another thread is trying to remove it;
+ * you cannot iterate as there is nothing to iterate.  The
+ * <em>head</em> of the queue is the element that the first queued
+ * inserting thread is trying to add to the queue; if there is no such
+ * queued thread then no element is available for removal and
+ * {@code poll()} will return {@code null}.  For purposes of other
+ * {@code Collection} methods (for example {@code contains}), a
+ * {@code SynchronousQueue} acts as an empty collection.  This queue
+ * does not permit {@code null} elements.
+ *
+ * <p>Synchronous queues are similar to rendezvous channels used in
+ * CSP and Ada. They are well suited for handoff designs, in which an
+ * object running in one thread must sync up with an object running
+ * in another thread in order to hand it some information, event, or
+ * task.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Collection} and {@link Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <E> the type of elements held in this queue
+ */
+public class SynchronousQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * This class implements extensions of the dual stack and dual
+     * queue algorithms described in "Nonblocking Concurrent Objects
+     * with Condition Synchronization", by W. N. Scherer III and
+     * M. L. Scott.  18th Annual Conf. on Distributed Computing,
+     * Oct. 2004 (see also
+     * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html).
+     * The (Lifo) stack is used for non-fair mode, and the (Fifo)
+     * queue for fair mode. The performance of the two is generally
+     * similar. Fifo usually supports higher throughput under
+     * contention but Lifo maintains higher thread locality in common
+     * applications.
+     *
+     * A dual queue (and similarly stack) is one that at any given
+     * time either holds "data" -- items provided by put operations,
+     * or "requests" -- slots representing take operations, or is
+     * empty. A call to "fulfill" (i.e., a call requesting an item
+     * from a queue holding data or vice versa) dequeues a
+     * complementary node.  The most interesting feature of these
+     * queues is that any operation can figure out which mode the
+     * queue is in, and act accordingly without needing locks.
+     *
+     * Both the queue and stack extend abstract class Transferer
+     * defining the single method transfer that does a put or a
+     * take. These are unified into a single method because in dual
+     * data structures, the put and take operations are symmetrical,
+     * so nearly all code can be combined. The resulting transfer
+     * methods are on the long side, but are easier to follow than
+     * they would be if broken up into nearly-duplicated parts.
+     *
+     * The queue and stack data structures share many conceptual
+     * similarities but very few concrete details. For simplicity,
+     * they are kept distinct so that they can later evolve
+     * separately.
+     *
+     * The algorithms here differ from the versions in the above paper
+     * in extending them for use in synchronous queues, as well as
+     * dealing with cancellation. The main differences include:
+     *
+     *  1. The original algorithms used bit-marked pointers, but
+     *     the ones here use mode bits in nodes, leading to a number
+     *     of further adaptations.
+     *  2. SynchronousQueues must block threads waiting to become
+     *     fulfilled.
+     *  3. Support for cancellation via timeout and interrupts,
+     *     including cleaning out cancelled nodes/threads
+     *     from lists to avoid garbage retention and memory depletion.
+     *
+     * Blocking is mainly accomplished using LockSupport park/unpark,
+     * except that nodes that appear to be the next ones to become
+     * fulfilled first spin a bit (on multiprocessors only). On very
+     * busy synchronous queues, spinning can dramatically improve
+     * throughput. And on less busy ones, the amount of spinning is
+     * small enough not to be noticeable.
+     *
+     * Cleaning is done in different ways in queues vs stacks.  For
+     * queues, we can almost always remove a node immediately in O(1)
+     * time (modulo retries for consistency checks) when it is
+     * cancelled. But if it may be pinned as the current tail, it must
+     * wait until some subsequent cancellation. For stacks, we need a
+     * potentially O(n) traversal to be sure that we can remove the
+     * node, but this can run concurrently with other threads
+     * accessing the stack.
+     *
+     * While garbage collection takes care of most node reclamation
+     * issues that otherwise complicate nonblocking algorithms, care
+     * is taken to "forget" references to data, other nodes, and
+     * threads that might be held on to long-term by blocked
+     * threads. In cases where setting to null would otherwise
+     * conflict with main algorithms, this is done by changing a
+     * node's link to now point to the node itself. This doesn't arise
+     * much for Stack nodes (because blocked threads do not hang on to
+     * old head pointers), but references in Queue nodes must be
+     * aggressively forgotten to avoid reachability of everything any
+     * node has ever referred to since arrival.
+     *
+     * The above steps improve throughput when many threads produce
+     * and/or consume data. But they don't help much with
+     * single-source / single-sink usages in which one side or the
+     * other is always transiently blocked, and so throughput is
+     * mainly a function of thread scheduling. This is not usually
+     * noticeably improved with bounded short spin-waits. Instead both
+     * forms of transfer try Thread.yield if apparently the sole
+     * waiter. This works well when there are more tasks that cores,
+     * which is expected to be the main usage context of this mode. In
+     * other cases, waiters may help with some bookkeeping, then
+     * park/unpark.
+     */
+
+    /**
+     * Shared internal API for dual stacks and queues.
+     */
+    abstract static class Transferer<E> {
+        /**
+         * Performs a put or take.
+         *
+         * @param e if non-null, the item to be handed to a consumer;
+         *          if null, requests that transfer return an item
+         *          offered by producer.
+         * @param timed if this operation should timeout
+         * @param nanos the timeout, in nanoseconds
+         * @return if non-null, the item provided or received; if null,
+         *         the operation failed due to timeout or interrupt --
+         *         the caller can distinguish which of these occurred
+         *         by checking Thread.interrupted.
+         */
+        abstract E transfer(E e, boolean timed, long nanos);
+    }
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1023L;
+
+    /** Dual stack */
+    static final class TransferStack<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual stack algorithm, differing,
+         * among other ways, by using "covering" nodes rather than
+         * bit-marked pointers: Fulfilling operations push on marker
+         * nodes (with FULFILLING bit set in mode) to reserve a spot
+         * to match a waiting node.
+         */
+
+        /* Modes for SNodes, ORed together in node fields */
+        /** Node represents an unfulfilled consumer */
+        static final int REQUEST    = 0;
+        /** Node represents an unfulfilled producer */
+        static final int DATA       = 1;
+        /** Node is fulfilling another unfulfilled DATA or REQUEST */
+        static final int FULFILLING = 2;
+
+        /** Returns true if m has fulfilling bit set. */
+        static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
+
+        /** Node class for TransferStacks. */
+        static final class SNode implements ForkJoinPool.ManagedBlocker {
+            volatile SNode next;        // next node in stack
+            volatile SNode match;       // the node matched to this
+            volatile Thread waiter;     // to control park/unpark
+            Object item;                // data; or null for REQUESTs
+            int mode;
+            // Note: item and mode fields don't need to be volatile
+            // since they are always written before, and read after,
+            // other volatile/atomic operations.
+
+            SNode(Object item) {
+                this.item = item;
+            }
+
+            boolean casNext(SNode cmp, SNode val) {
+                return cmp == next &&
+                    SNEXT.compareAndSet(this, cmp, val);
+            }
+
+            /**
+             * Tries to match node s to this node, if so, waking up thread.
+             * Fulfillers call tryMatch to identify their waiters.
+             * Waiters block until they have been matched.
+             *
+             * @param s the node to match
+             * @return true if successfully matched to s
+             */
+            boolean tryMatch(SNode s) {
+                SNode m; Thread w;
+                if ((m = match) == null) {
+                    if (SMATCH.compareAndSet(this, null, s)) {
+                        if ((w = waiter) != null)
+                            LockSupport.unpark(w);
+                        return true;
+                    }
+                    else
+                        m = match;
+                }
+                return m == s;
+            }
+
+            /**
+             * Tries to cancel a wait by matching node to itself.
+             */
+            boolean tryCancel() {
+                return SMATCH.compareAndSet(this, null, this);
+            }
+
+            boolean isCancelled() {
+                return match == this;
+            }
+
+            public final boolean isReleasable() {
+                return match != null || Thread.currentThread().isInterrupted();
+            }
+
+            public final boolean block() {
+                while (!isReleasable()) LockSupport.park();
+                return true;
+            }
+
+            void forgetWaiter() {
+                SWAITER.setOpaque(this, null);
+            }
+
+            // VarHandle mechanics
+            private static final VarHandle SMATCH;
+            private static final VarHandle SNEXT;
+            private static final VarHandle SWAITER;
+            static {
+                try {
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
+                    SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
+                    SWAITER = l.findVarHandle(SNode.class, "waiter", Thread.class);
+                } catch (ReflectiveOperationException e) {
+                    throw new ExceptionInInitializerError(e);
+                }
+            }
+        }
+
+        /** The head (top) of the stack */
+        volatile SNode head;
+
+        boolean casHead(SNode h, SNode nh) {
+            return h == head &&
+                SHEAD.compareAndSet(this, h, nh);
+        }
+
+        /**
+         * Creates or resets fields of a node. Called only from transfer
+         * where the node to push on stack is lazily created and
+         * reused when possible to help reduce intervals between reads
+         * and CASes of head and to avoid surges of garbage when CASes
+         * to push nodes fail due to contention.
+         */
+        static SNode snode(SNode s, Object e, SNode next, int mode) {
+            if (s == null) s = new SNode(e);
+            s.mode = mode;
+            s.next = next;
+            return s;
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /*
+             * Basic algorithm is to loop trying one of three actions:
+             *
+             * 1. If apparently empty or already containing nodes of same
+             *    mode, try to push node on stack and wait for a match,
+             *    returning it, or null if cancelled.
+             *
+             * 2. If apparently containing node of complementary mode,
+             *    try to push a fulfilling node on to stack, match
+             *    with corresponding waiting node, pop both from
+             *    stack, and return matched item. The matching or
+             *    unlinking might not actually be necessary because of
+             *    other threads performing action 3:
+             *
+             * 3. If top of stack already holds another fulfilling node,
+             *    help it out by doing its match and/or pop
+             *    operations, and then continue. The code for helping
+             *    is essentially the same as for fulfilling, except
+             *    that it doesn't return the item.
+             */
+
+            SNode s = null; // constructed/reused as needed
+            int mode = (e == null) ? REQUEST : DATA;
+
+            for (;;) {
+                SNode h = head;
+                if (h == null || h.mode == mode) {  // empty or same-mode
+                    if (timed && nanos <= 0L) {     // can't wait
+                        if (h != null && h.isCancelled())
+                            casHead(h, h.next);     // pop cancelled node
+                        else
+                            return null;
+                    } else if (casHead(h, s = snode(s, e, h, mode))) {
+                        long deadline = timed ? System.nanoTime() + nanos : 0L;
+                        Thread w = Thread.currentThread();
+                        int stat = -1; // -1: may yield, +1: park, else 0
+                        SNode m;                    // await fulfill or cancel
+                        while ((m = s.match) == null) {
+                            if ((timed &&
+                                 (nanos = deadline - System.nanoTime()) <= 0) ||
+                                w.isInterrupted()) {
+                                if (s.tryCancel()) {
+                                    clean(s);       // wait cancelled
+                                    return null;
+                                }
+                            } else if ((m = s.match) != null) {
+                                break;              // recheck
+                            } else if (stat <= 0) {
+                                if (stat < 0 && h == null && head == s) {
+                                    stat = 0;       // yield once if was empty
+                                    Thread.yield();
+                                } else {
+                                    stat = 1;
+                                    s.waiter = w;   // enable signal
+                                }
+                            } else if (!timed) {
+                                LockSupport.setCurrentBlocker(this);
+                                try {
+                                    ForkJoinPool.managedBlock(s);
+                                } catch (InterruptedException cannotHappen) { }
+                                LockSupport.setCurrentBlocker(null);
+                            } else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                                LockSupport.parkNanos(this, nanos);
+                        }
+                        if (stat == 1)
+                            s.forgetWaiter();
+                        Object result = (mode == REQUEST) ? m.item : s.item;
+                        if (h != null && h.next == s)
+                            casHead(h, s.next);     // help fulfiller
+                        return (E) result;
+                    }
+                } else if (!isFulfilling(h.mode)) { // try to fulfill
+                    if (h.isCancelled())            // already cancelled
+                        casHead(h, h.next);         // pop and retry
+                    else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
+                        for (;;) { // loop until matched or waiters disappear
+                            SNode m = s.next;       // m is s's match
+                            if (m == null) {        // all waiters are gone
+                                casHead(s, null);   // pop fulfill node
+                                s = null;           // use new node next time
+                                break;              // restart main loop
+                            }
+                            SNode mn = m.next;
+                            if (m.tryMatch(s)) {
+                                casHead(s, mn);     // pop both s and m
+                                return (E) ((mode == REQUEST) ? m.item : s.item);
+                            } else                  // lost match
+                                s.casNext(m, mn);   // help unlink
+                        }
+                    }
+                } else {                            // help a fulfiller
+                    SNode m = h.next;               // m is h's match
+                    if (m == null)                  // waiter is gone
+                        casHead(h, null);           // pop fulfilling node
+                    else {
+                        SNode mn = m.next;
+                        if (m.tryMatch(h))          // help match
+                            casHead(h, mn);         // pop both h and m
+                        else                        // lost match
+                            h.casNext(m, mn);       // help unlink
+                    }
+                }
+            }
+        }
+
+        /**
+         * Unlinks s from the stack.
+         */
+        void clean(SNode s) {
+            s.item = null;   // forget item
+            s.forgetWaiter();
+
+            /*
+             * At worst we may need to traverse entire stack to unlink
+             * s. If there are multiple concurrent calls to clean, we
+             * might not see s if another thread has already removed
+             * it. But we can stop when we see any node known to
+             * follow s. We use s.next unless it too is cancelled, in
+             * which case we try the node one past. We don't check any
+             * further because we don't want to doubly traverse just to
+             * find sentinel.
+             */
+
+            SNode past = s.next;
+            if (past != null && past.isCancelled())
+                past = past.next;
+
+            // Absorb cancelled nodes at head
+            SNode p;
+            while ((p = head) != null && p != past && p.isCancelled())
+                casHead(p, p.next);
+
+            // Unsplice embedded nodes
+            while (p != null && p != past) {
+                SNode n = p.next;
+                if (n != null && n.isCancelled())
+                    p.casNext(n, n.next);
+                else
+                    p = n;
+            }
+        }
+
+        // VarHandle mechanics
+        private static final VarHandle SHEAD;
+        static {
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+    }
+
+    /** Dual Queue */
+    static final class TransferQueue<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual queue algorithm, differing,
+         * among other ways, by using modes within nodes rather than
+         * marked pointers. The algorithm is a little simpler than
+         * that for stacks because fulfillers do not need explicit
+         * nodes, and matching is done by CAS'ing QNode.item field
+         * from non-null to null (for put) or vice versa (for take).
+         */
+
+        /** Node class for TransferQueue. */
+        static final class QNode implements ForkJoinPool.ManagedBlocker {
+            volatile QNode next;          // next node in queue
+            volatile Object item;         // CAS'ed to or from null
+            volatile Thread waiter;       // to control park/unpark
+            final boolean isData;
+
+            QNode(Object item, boolean isData) {
+                this.item = item;
+                this.isData = isData;
+            }
+
+            boolean casNext(QNode cmp, QNode val) {
+                return next == cmp &&
+                    QNEXT.compareAndSet(this, cmp, val);
+            }
+
+            boolean casItem(Object cmp, Object val) {
+                return item == cmp &&
+                    QITEM.compareAndSet(this, cmp, val);
+            }
+
+            /**
+             * Tries to cancel by CAS'ing ref to this as item.
+             */
+            boolean tryCancel(Object cmp) {
+                return QITEM.compareAndSet(this, cmp, this);
+            }
+
+            boolean isCancelled() {
+                return item == this;
+            }
+
+            /**
+             * Returns true if this node is known to be off the queue
+             * because its next pointer has been forgotten due to
+             * an advanceHead operation.
+             */
+            boolean isOffList() {
+                return next == this;
+            }
+
+            void forgetWaiter() {
+                QWAITER.setOpaque(this, null);
+            }
+
+            boolean isFulfilled() {
+                Object x;
+                return isData == ((x = item) == null) || x == this;
+            }
+
+            public final boolean isReleasable() {
+                Object x;
+                return isData == ((x = item) == null) || x == this ||
+                    Thread.currentThread().isInterrupted();
+            }
+
+            public final boolean block() {
+                while (!isReleasable()) LockSupport.park();
+                return true;
+            }
+
+            // VarHandle mechanics
+            private static final VarHandle QITEM;
+            private static final VarHandle QNEXT;
+            private static final VarHandle QWAITER;
+            static {
+                try {
+                    MethodHandles.Lookup l = MethodHandles.lookup();
+                    QITEM = l.findVarHandle(QNode.class, "item", Object.class);
+                    QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
+                    QWAITER = l.findVarHandle(QNode.class, "waiter", Thread.class);
+                } catch (ReflectiveOperationException e) {
+                    throw new ExceptionInInitializerError(e);
+                }
+            }
+        }
+
+        /** Head of queue */
+        transient volatile QNode head;
+        /** Tail of queue */
+        transient volatile QNode tail;
+        /**
+         * Reference to a cancelled node that might not yet have been
+         * unlinked from queue because it was the last inserted node
+         * when it was cancelled.
+         */
+        transient volatile QNode cleanMe;
+
+        TransferQueue() {
+            QNode h = new QNode(null, false); // initialize to dummy node.
+            head = h;
+            tail = h;
+        }
+
+        /**
+         * Tries to cas nh as new head; if successful, unlink
+         * old head's next node to avoid garbage retention.
+         */
+        void advanceHead(QNode h, QNode nh) {
+            if (h == head &&
+                QHEAD.compareAndSet(this, h, nh))
+                h.next = h; // forget old next
+        }
+
+        /**
+         * Tries to cas nt as new tail.
+         */
+        void advanceTail(QNode t, QNode nt) {
+            if (tail == t)
+                QTAIL.compareAndSet(this, t, nt);
+        }
+
+        /**
+         * Tries to CAS cleanMe slot.
+         */
+        boolean casCleanMe(QNode cmp, QNode val) {
+            return cleanMe == cmp &&
+                QCLEANME.compareAndSet(this, cmp, val);
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /* Basic algorithm is to loop trying to take either of
+             * two actions:
+             *
+             * 1. If queue apparently empty or holding same-mode nodes,
+             *    try to add node to queue of waiters, wait to be
+             *    fulfilled (or cancelled) and return matching item.
+             *
+             * 2. If queue apparently contains waiting items, and this
+             *    call is of complementary mode, try to fulfill by CAS'ing
+             *    item field of waiting node and dequeuing it, and then
+             *    returning matching item.
+             *
+             * In each case, along the way, check for and try to help
+             * advance head and tail on behalf of other stalled/slow
+             * threads.
+             *
+             * The loop starts off with a null check guarding against
+             * seeing uninitialized head or tail values. This never
+             * happens in current SynchronousQueue, but could if
+             * callers held non-volatile/final ref to the
+             * transferer. The check is here anyway because it places
+             * null checks at top of loop, which is usually faster
+             * than having them implicitly interspersed.
+             */
+
+            QNode s = null;                  // constructed/reused as needed
+            boolean isData = (e != null);
+            for (;;) {
+                QNode t = tail, h = head, m, tn;         // m is node to fulfill
+                if (t == null || h == null)
+                    ;                                    // inconsistent
+                else if (h == t || t.isData == isData) { // empty or same-mode
+                    if (t != tail)                       // inconsistent
+                        ;
+                    else if ((tn = t.next) != null)      // lagging tail
+                        advanceTail(t, tn);
+                    else if (timed && nanos <= 0L)       // can't wait
+                        return null;
+                    else if (t.casNext(null, (s != null) ? s :
+                                       (s = new QNode(e, isData)))) {
+                        advanceTail(t, s);
+                        long deadline = timed ? System.nanoTime() + nanos : 0L;
+                        Thread w = Thread.currentThread();
+                        int stat = -1; // same idea as TransferStack
+                        Object item;
+                        while ((item = s.item) == e) {
+                            if ((timed &&
+                                 (nanos = deadline - System.nanoTime()) <= 0) ||
+                                w.isInterrupted()) {
+                                if (s.tryCancel(e)) {
+                                    clean(t, s);
+                                    return null;
+                                }
+                            } else if ((item = s.item) != e) {
+                                break;                   // recheck
+                            } else if (stat <= 0) {
+                                if (t.next == s) {
+                                    if (stat < 0 && t.isFulfilled()) {
+                                        stat = 0;        // yield once if first
+                                        Thread.yield();
+                                    }
+                                    else {
+                                        stat = 1;
+                                        s.waiter = w;
+                                    }
+                                }
+                            } else if (!timed) {
+                                LockSupport.setCurrentBlocker(this);
+                                try {
+                                    ForkJoinPool.managedBlock(s);
+                                } catch (InterruptedException cannotHappen) { }
+                                LockSupport.setCurrentBlocker(null);
+                            }
+                            else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                                LockSupport.parkNanos(this, nanos);
+                        }
+                        if (stat == 1)
+                            s.forgetWaiter();
+                        if (!s.isOffList()) {            // not already unlinked
+                            advanceHead(t, s);           // unlink if head
+                            if (item != null)            // and forget fields
+                                s.item = s;
+                        }
+                        return (item != null) ? (E)item : e;
+                    }
+
+                } else if ((m = h.next) != null && t == tail && h == head) {
+                    Thread waiter;
+                    Object x = m.item;
+                    boolean fulfilled = ((isData == (x == null)) &&
+                                         x != m && m.casItem(x, e));
+                    advanceHead(h, m);                    // (help) dequeue
+                    if (fulfilled) {
+                        if ((waiter = m.waiter) != null)
+                            LockSupport.unpark(waiter);
+                        return (x != null) ? (E)x : e;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Gets rid of cancelled node s with original predecessor pred.
+         */
+        void clean(QNode pred, QNode s) {
+            s.forgetWaiter();
+            /*
+             * At any given time, exactly one node on list cannot be
+             * deleted -- the last inserted node. To accommodate this,
+             * if we cannot delete s, we save its predecessor as
+             * "cleanMe", deleting the previously saved version
+             * first. At least one of node s or the node previously
+             * saved can always be deleted, so this always terminates.
+             */
+            while (pred.next == s) { // Return early if already unlinked
+                QNode h = head;
+                QNode hn = h.next;   // Absorb cancelled first node as head
+                if (hn != null && hn.isCancelled()) {
+                    advanceHead(h, hn);
+                    continue;
+                }
+                QNode t = tail;      // Ensure consistent read for tail
+                if (t == h)
+                    return;
+                QNode tn = t.next;
+                if (t != tail)
+                    continue;
+                if (tn != null) {
+                    advanceTail(t, tn);
+                    continue;
+                }
+                if (s != t) {        // If not tail, try to unsplice
+                    QNode sn = s.next;
+                    if (sn == s || pred.casNext(s, sn))
+                        return;
+                }
+                QNode dp = cleanMe;
+                if (dp != null) {    // Try unlinking previous cancelled node
+                    QNode d = dp.next;
+                    QNode dn;
+                    if (d == null ||               // d is gone or
+                        d == dp ||                 // d is off list or
+                        !d.isCancelled() ||        // d not cancelled or
+                        (d != t &&                 // d not tail and
+                         (dn = d.next) != null &&  //   has successor
+                         dn != d &&                //   that is on list
+                         dp.casNext(d, dn)))       // d unspliced
+                        casCleanMe(dp, null);
+                    if (dp == pred)
+                        return;      // s is already saved node
+                } else if (casCleanMe(null, pred))
+                    return;          // Postpone cleaning s
+            }
+        }
+
+        // VarHandle mechanics
+        private static final VarHandle QHEAD;
+        private static final VarHandle QTAIL;
+        private static final VarHandle QCLEANME;
+        static {
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                QHEAD = l.findVarHandle(TransferQueue.class, "head",
+                                        QNode.class);
+                QTAIL = l.findVarHandle(TransferQueue.class, "tail",
+                                        QNode.class);
+                QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
+                                           QNode.class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+    }
+
+    /**
+     * The transferer. Set only in constructor, but cannot be declared
+     * as final without further complicating serialization.  Since
+     * this is accessed only at most once per public method, there
+     * isn't a noticeable performance penalty for using volatile
+     * instead of final here.
+     */
+    private transient volatile Transferer<E> transferer;
+
+    /**
+     * Creates a {@code SynchronousQueue} with nonfair access policy.
+     */
+    public SynchronousQueue() {
+        this(false);
+    }
+
+    /**
+     * Creates a {@code SynchronousQueue} with the specified fairness policy.
+     *
+     * @param fair if true, waiting threads contend in FIFO order for
+     *        access; otherwise the order is unspecified.
+     */
+    public SynchronousQueue(boolean fair) {
+        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
+    }
+
+    /**
+     * Adds the specified element to this queue, waiting if necessary for
+     * another thread to receive it.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, false, 0) == null) {
+            Thread.interrupted();
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * up to the specified wait time for another thread to receive it.
+     *
+     * @return {@code true} if successful, or {@code false} if the
+     *         specified waiting time elapses before a consumer appears
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Inserts the specified element into this queue, if another thread is
+     * waiting to receive it.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        return transferer.transfer(e, true, 0) != null;
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * for another thread to insert it.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        E e = transferer.transfer(null, false, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting
+     * if necessary up to the specified wait time, for another thread
+     * to insert it.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is present
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = transferer.transfer(null, true, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, if another thread
+     * is currently making an element available.
+     *
+     * @return the head of this queue, or {@code null} if no
+     *         element is available
+     */
+    public E poll() {
+        return transferer.transfer(null, true, 0);
+    }
+
+    /**
+     * Always returns {@code true}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return {@code true}
+     */
+    public boolean isEmpty() {
+        return true;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int size() {
+        return 0;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int remainingCapacity() {
+        return 0;
+    }
+
+    /**
+     * Does nothing.
+     * A {@code SynchronousQueue} has no internal capacity.
+     */
+    public void clear() {
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element
+     * @return {@code false}
+     */
+    public boolean contains(Object o) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element to remove
+     * @return {@code false}
+     */
+    public boolean remove(Object o) {
+        return false;
+    }
+
+    /**
+     * Returns {@code false} unless the given collection is empty.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false} unless given collection is empty
+     */
+    public boolean containsAll(Collection<?> c) {
+        return c.isEmpty();
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean removeAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean retainAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code null}.
+     * A {@code SynchronousQueue} does not return elements
+     * unless actively waited on.
+     *
+     * @return {@code null}
+     */
+    public E peek() {
+        return null;
+    }
+
+    /**
+     * Returns an empty iterator in which {@code hasNext} always returns
+     * {@code false}.
+     *
+     * @return an empty iterator
+     */
+    public Iterator<E> iterator() {
+        return Collections.emptyIterator();
+    }
+
+    /**
+     * Returns an empty spliterator in which calls to
+     * {@link Spliterator#trySplit() trySplit} always return {@code null}.
+     *
+     * @return an empty spliterator
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.emptySpliterator();
+    }
+
+    /**
+     * Returns a zero-length array.
+     * @return a zero-length array
+     */
+    public Object[] toArray() {
+        return new Object[0];
+    }
+
+    /**
+     * Sets the zeroth element of the specified array to {@code null}
+     * (if the array has non-zero length) and returns it.
+     *
+     * @param a the array
+     * @return the specified array
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        if (a.length > 0)
+            a[0] = null;
+        return a;
+    }
+
+    /**
+     * Always returns {@code "[]"}.
+     * @return {@code "[]"}
+     */
+    public String toString() {
+        return "[]";
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null; n++)
+            c.add(e);
+        return n;
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null; n++)
+            c.add(e);
+        return n;
+    }
+
+    /*
+     * To cope with serialization strategy in the 1.5 version of
+     * SynchronousQueue, we declare some unused classes and fields
+     * that exist solely to enable serializability across versions.
+     * These fields are never used, so are initialized only if this
+     * object is ever serialized or deserialized.
+     */
+
+    @SuppressWarnings("serial")
+    static class WaitQueue implements java.io.Serializable { }
+    static class LifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3633113410248163686L;
+    }
+    static class FifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3623113410248163686L;
+    }
+    private ReentrantLock qlock;
+    private WaitQueue waitingProducers;
+    private WaitQueue waitingConsumers;
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        boolean fair = transferer instanceof TransferQueue;
+        if (fair) {
+            qlock = new ReentrantLock(true);
+            waitingProducers = new FifoWaitQueue();
+            waitingConsumers = new FifoWaitQueue();
+        }
+        else {
+            qlock = new ReentrantLock();
+            waitingProducers = new LifoWaitQueue();
+            waitingConsumers = new LifoWaitQueue();
+        }
+        s.defaultWriteObject();
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        if (waitingProducers instanceof FifoWaitQueue)
+            transferer = new TransferQueue<E>();
+        else
+            transferer = new TransferStack<E>();
+    }
+
+    static {
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/ThreadFactory.java b/android-35/java/util/concurrent/ThreadFactory.java
new file mode 100644
index 0000000..ac7afa0
--- /dev/null
+++ b/android-35/java/util/concurrent/ThreadFactory.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that creates new threads on demand.  Using thread factories
+ * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
+ * enabling applications to use special thread subclasses, priorities, etc.
+ *
+ * <p>
+ * The simplest implementation of this interface is just:
+ * <pre> {@code
+ * class SimpleThreadFactory implements ThreadFactory {
+ *   public Thread newThread(Runnable r) {
+ *     return new Thread(r);
+ *   }
+ * }}</pre>
+ *
+ * The {@link Executors#defaultThreadFactory} method provides a more
+ * useful simple implementation, that sets the created thread context
+ * to known values before returning it.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ThreadFactory {
+
+    /**
+     * Constructs a new {@code Thread}.  Implementations may also initialize
+     * priority, name, daemon status, {@code ThreadGroup}, etc.
+     *
+     * @param r a runnable to be executed by new thread instance
+     * @return constructed thread, or {@code null} if the request to
+     *         create a thread is rejected
+     */
+    Thread newThread(Runnable r);
+}
diff --git a/android-35/java/util/concurrent/ThreadLocalRandom.java b/android-35/java/util/concurrent/ThreadLocalRandom.java
new file mode 100644
index 0000000..de8dd5f
--- /dev/null
+++ b/android-35/java/util/concurrent/ThreadLocalRandom.java
@@ -0,0 +1,671 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Additional modifications by Guy Steele in 2019 to refactor the code
+ * and to implement the {@link RandomGenerator} interface.
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.math.BigInteger;
+import java.security.AccessControlContext;
+import java.util.Map;
+import java.util.Random;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.random.RandomGenerator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import jdk.internal.util.random.RandomSupport;
+import jdk.internal.util.random.RandomSupport.*;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.misc.VM;
+
+/**
+ * A random number generator (with period 2<sup>64</sup>) 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
+ * accidentally share a {@code ThreadLocalRandom} across multiple threads.
+ *
+ * <p>This class also provides additional commonly used bounded random
+ * generation methods.
+ *
+ * <p>Instances of {@code ThreadLocalRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+
+@RandomGeneratorProperties(
+        name = "ThreadLocalRandom",
+        i = 64, j = 0, k = 0,
+        equidistribution = 1
+)
+public class ThreadLocalRandom extends Random {
+    /*
+     * This class implements the java.util.Random API (and subclasses
+     * Random) using a single static instance that accesses 64 bits of
+     * random number state held in class java.lang.Thread (field
+     * threadLocalRandomSeed). In doing so, it also provides a home
+     * for managing package-private utilities that rely on exactly the
+     * same state as needed to maintain the ThreadLocalRandom
+     * instances. We leverage the need for an initialization flag
+     * field to also use it as a "probe" -- a self-adjusting thread
+     * hash used for contention avoidance, as well as a secondary
+     * simpler (xorShift) random seed that is conservatively used to
+     * avoid otherwise surprising users by hijacking the
+     * ThreadLocalRandom sequence.  The dual use is a marriage of
+     * convenience, but is a simple and efficient way of reducing
+     * application-level overhead and footprint of most concurrent
+     * programs. Even more opportunistically, we also define here
+     * other package-private utilities that access Thread class
+     * fields.
+     *
+     * Even though this class subclasses java.util.Random, it uses the
+     * same basic algorithm as java.util.SplittableRandom.  (See its
+     * internal documentation for explanations, which are not repeated
+     * here.)  Note that ThreadLocalRandom is not a "splittable" generator
+     * (it does not support the split method), but it behaves as if
+     * one instance of the SplittableRandom algorithm had been
+     * created for each thread, each with a distinct gamma parameter
+     * (calculated from the thread id).
+     *
+     * Because this class is in a different package than class Thread,
+     * field access methods use Unsafe to bypass access control rules.
+     * To conform to the requirements of the Random superclass
+     * constructor, the common static ThreadLocalRandom maintains an
+     * "initialized" field for the sake of rejecting user calls to
+     * setSeed while still allowing a call from constructor.  Note
+     * that serialization is completely unnecessary because there is
+     * only a static singleton.  But we generate a serial form
+     * containing "rnd" and "initialized" fields to ensure
+     * compatibility across versions.
+     *
+     * Implementations of non-core methods are mostly the same as in
+     * SplittableRandom, that were in part derived from a previous
+     * version of this class.
+     *
+     * This implementation of ThreadLocalRandom overrides the
+     * definition of the nextGaussian() method in the class Random,
+     * and instead uses the ziggurat-based algorithm that is the
+     * default for the RandomGenerator interface.
+     */
+
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
+    }
+
+    /**
+     * Field used only during singleton initialization.
+     * True when constructor completes.
+     */
+    boolean initialized;
+
+    /** Constructor used only for static singleton */
+    private ThreadLocalRandom() {
+        initialized = true; // false during super() call
+    }
+
+    /**
+     * Initialize Thread fields for the current thread.  Called only
+     * when Thread.threadLocalRandomProbe is zero, indicating that a
+     * thread local seed value needs to be generated. Note that even
+     * though the initialization is purely thread-local, we need to
+     * rely on (static) atomic generators to initialize the values.
+     */
+    static final void localInit() {
+        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
+        int probe = (p == 0) ? 1 : p; // skip 0
+        long seed = RandomSupport.mixMurmur64(seeder.getAndAdd(SEEDER_INCREMENT));
+        Thread t = Thread.currentThread();
+        U.putLong(t, SEED, seed);
+        U.putInt(t, PROBE, probe);
+    }
+
+    /**
+     * Returns the current thread's {@code ThreadLocalRandom} object.
+     * Methods of this object should be called only by the current thread,
+     * not by other threads.
+     *
+     * @return the current thread's {@code ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom current() {
+        if (U.getInt(Thread.currentThread(), PROBE) == 0)
+            localInit();
+        return instance;
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.  Setting seeds in
+     * this generator is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void setSeed(long seed) {
+        // only allow call from super() constructor
+        if (initialized)
+            throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Update the thread local seed value by adding to it the sum
+     * of {@code GOLDEN_GAMMA} (an odd value) and twice the thread id.
+     * This sum is always odd (to guarantee that the generator
+     * has maximum period) and is different for different threads.
+     * Because thread id values are allocated consecutively starting
+     * from 0, the high 32 bits of this sum will be the same as the
+     * high 32 bits of {@code GOLDEN_GAMMA} unless an extremely large
+     * number of threads have been created, and so the overall
+     * value added to the thread local seed value will have at least
+     * fourteen 01 and 10 transitions (see the documentation for the
+     * method {@code mixGamma} in class {@code SplittableRandom}),
+     * which should provide adequate statistical quality for
+     * applications likely to use {@code ThreadLocalRandom}.
+     */
+    final long nextSeed() {
+        Thread t; long r; // read and update per-thread seed
+        U.putLong(t = Thread.currentThread(), SEED,
+                  r = U.getLong(t, SEED) + (t.getId() << 1) + GOLDEN_GAMMA);
+        return r;
+    }
+
+    /**
+     * Generates a pseudorandom number with the indicated number of
+     * low-order bits.  Because this class has no subclasses, this
+     * method cannot be invoked or overridden.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     */
+    protected int next(int bits) {
+        return nextInt() >>> (32 - bits);
+    }
+
+    // Within-package utilities
+
+    /*
+     * Descriptions of the usages of the methods below can be found in
+     * the classes that use them. Briefly, a thread's "probe" value is
+     * a non-zero hash code that (probably) does not collide with
+     * other existing threads with respect to any power of two
+     * collision space. When it does collide, it is pseudo-randomly
+     * adjusted (using a Marsaglia XorShift). The nextSecondarySeed
+     * method is used in the same contexts as ThreadLocalRandom, but
+     * only for transient usages such as random adaptive spin/block
+     * sequences for which a cheap RNG suffices and for which it could
+     * in principle disrupt user-visible statistical properties of the
+     * main ThreadLocalRandom if we were to use it.
+     *
+     * Note: Because of package-protection issues, versions of some
+     * these methods also appear in some subpackage classes.
+     */
+
+    /**
+     * Returns the probe value for the current thread without forcing
+     * initialization. Note that invoking ThreadLocalRandom.current()
+     * can be used to force initialization on zero return.
+     */
+    static final int getProbe() {
+        return U.getInt(Thread.currentThread(), PROBE);
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        U.putInt(Thread.currentThread(), PROBE, probe);
+        return probe;
+    }
+
+    /**
+     * Returns the pseudo-randomly initialized or updated secondary seed.
+     */
+    static final int nextSecondarySeed() {
+        int r;
+        Thread t = Thread.currentThread();
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
+            r ^= r << 13;   // xorshift
+            r ^= r >>> 17;
+            r ^= r << 5;
+        }
+        else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
+            r = 1; // avoid zero
+        U.putInt(t, SECONDARY, r);
+        return r;
+    }
+
+    // Support for other package-private ThreadLocal access
+
+    /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    static final void eraseThreadLocals(Thread thread) {
+        U.putReference(thread, THREADLOCALS, null);
+        U.putReference(thread, INHERITABLETHREADLOCALS, null);
+    }
+
+    static final void setInheritedAccessControlContext(Thread thread,
+                                                       @SuppressWarnings("removal") AccessControlContext acc) {
+        U.putReferenceRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -5851777807851030925L;
+
+    /**
+     * @serialField rnd long
+     *              seed for random computations
+     * @serialField initialized boolean
+     *              always true
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("rnd", long.class),
+        new ObjectStreamField("initialized", boolean.class),
+    };
+
+    /**
+     * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
+        fields.put("initialized", true);
+        s.writeFields();
+    }
+
+    /**
+     * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
+     * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
+     */
+    private Object readResolve() {
+        return current();
+    }
+
+    // Static initialization
+
+    /**
+     * The seed increment.  This must be an odd value for the generator to
+     * have the maximum period (2 to the 64th power).
+     *
+     * The value 0x9e3779b97f4a7c15L is odd, and moreover consists of the
+     * first 64 bits of the fractional part of the golden ratio,
+     * which is known to generate good Weyl sequences.
+     */
+    private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The increment for generating probe values.
+     */
+    private static final int PROBE_INCREMENT = 0x9e3779b9;
+
+    /**
+     * The increment of seeder per new instance.
+     */
+    private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
+
+    // IllegalArgumentException messages
+    static final String BAD_BOUND = "bound must be positive";
+    static final String BAD_RANGE = "bound must be greater than origin";
+    static final String BAD_SIZE  = "size must be non-negative";
+
+    // Unsafe mechanics
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long SEED
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSeed");
+    private static final long PROBE
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomProbe");
+    private static final long SECONDARY
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSecondarySeed");
+    private static final long THREADLOCALS
+        = U.objectFieldOffset(Thread.class, "threadLocals");
+    private static final long INHERITABLETHREADLOCALS
+        = U.objectFieldOffset(Thread.class, "inheritableThreadLocals");
+    private static final long INHERITEDACCESSCONTROLCONTEXT
+        = U.objectFieldOffset(Thread.class, "inheritedAccessControlContext");
+
+    /** Generates per-thread initialization/probe field */
+    private static final AtomicInteger probeGenerator = new AtomicInteger();
+
+    /** The common ThreadLocalRandom */
+    private static final ThreadLocalRandom instance = new ThreadLocalRandom();
+
+    /**
+     * The next seed for default constructors.
+     */
+    private static final AtomicLong seeder
+        = new AtomicLong(RandomSupport.mixMurmur64(System.currentTimeMillis()) ^
+                         RandomSupport.mixMurmur64(System.nanoTime()));
+
+    // at end of <clinit> to survive static initialization circularity
+    static {
+        String sec = VM.getSavedProperty("java.util.secureRandomSeed");
+        if (Boolean.parseBoolean(sec)) {
+            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
+            long s = (long)seedBytes[0] & 0xffL;
+            for (int i = 1; i < 8; ++i)
+                s = (s << 8) | ((long)seedBytes[i] & 0xffL);
+            seeder.set(s);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static final class ThreadLocalRandomProxy extends Random {
+        static final Random PROXY = new ThreadLocalRandomProxy();
+
+        public int nextInt() {
+            return ThreadLocalRandom.current().nextInt();
+        }
+
+        public long nextLong() {
+            return ThreadLocalRandom.current().nextLong();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean nextBoolean() {
+        return super.nextBoolean();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    @Override
+    public int nextInt(int bound) {
+        return super.nextInt(bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    @Override
+    public int nextInt(int origin, int bound) {
+        return super.nextInt(origin, bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long nextLong() {
+        return RandomSupport.mixMurmur64(nextSeed());
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    @Override
+    public long nextLong(long bound) {
+        return super.nextLong(bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    @Override
+    public long nextLong(long origin, long bound) {
+        return super.nextLong(origin, bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public float nextFloat() {
+        return super.nextFloat();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implNote {@inheritDoc}
+     */
+    @Override
+    public float nextFloat(float bound) {
+         return super.nextFloat(bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implNote {@inheritDoc}
+     */
+    @Override
+    public float nextFloat(float origin, float bound) {
+        return super.nextFloat(origin, bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public double nextDouble() {
+        return super.nextDouble();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implNote {@inheritDoc}
+     */
+    @Override
+    public double nextDouble(double bound) {
+        return super.nextDouble(bound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @implNote {@inheritDoc}
+     */
+    @Override
+    public double nextDouble(double origin, double bound) {
+        return super.nextDouble(origin, bound);
+    }
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(long streamSize) {
+        return AbstractSpliteratorGenerator.ints(ThreadLocalRandomProxy.PROXY, streamSize);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code ints(Long.MAX_VALUE)}.
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints() {
+        return AbstractSpliteratorGenerator.ints(ThreadLocalRandomProxy.PROXY);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) {
+        return AbstractSpliteratorGenerator.ints(ThreadLocalRandomProxy.PROXY, streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        return AbstractSpliteratorGenerator.ints(ThreadLocalRandomProxy.PROXY, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long streamSize) {
+        return AbstractSpliteratorGenerator.longs(ThreadLocalRandomProxy.PROXY, streamSize);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code longs(Long.MAX_VALUE)}.
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs() {
+        return AbstractSpliteratorGenerator.longs(ThreadLocalRandomProxy.PROXY);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long streamSize, long randomNumberOrigin, long randomNumberBound) {
+        return AbstractSpliteratorGenerator.longs(ThreadLocalRandomProxy.PROXY, streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        return AbstractSpliteratorGenerator.longs(ThreadLocalRandomProxy.PROXY, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(long streamSize) {
+        return AbstractSpliteratorGenerator.doubles(ThreadLocalRandomProxy.PROXY, streamSize);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code doubles(Long.MAX_VALUE)}.
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles() {
+        return AbstractSpliteratorGenerator.doubles(ThreadLocalRandomProxy.PROXY);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
+        return AbstractSpliteratorGenerator.doubles(ThreadLocalRandomProxy.PROXY, streamSize, randomNumberOrigin, randomNumberBound);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @implNote This method is implemented to be equivalent to
+     *           {@code doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        return AbstractSpliteratorGenerator.doubles(ThreadLocalRandomProxy.PROXY, randomNumberOrigin, randomNumberBound);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/ThreadPoolExecutor.java b/android-35/java/util/concurrent/ThreadPoolExecutor.java
new file mode 100644
index 0000000..fff2beb
--- /dev/null
+++ b/android-35/java/util/concurrent/ThreadPoolExecutor.java
@@ -0,0 +1,2146 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// 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
+ * using {@link Executors} factory methods.
+ *
+ * <p>Thread pools address two different problems: they usually
+ * provide improved performance when executing large numbers of
+ * asynchronous tasks, due to reduced per-task invocation overhead,
+ * and they provide a means of bounding and managing the resources,
+ * including threads, consumed when executing a collection of tasks.
+ * Each {@code ThreadPoolExecutor} also maintains some basic
+ * statistics, such as the number of completed tasks.
+ *
+ * <p>To be useful across a wide range of contexts, this class
+ * provides many adjustable parameters and extensibility
+ * hooks. However, programmers are urged to use the more convenient
+ * {@link Executors} factory methods {@link
+ * Executors#newCachedThreadPool} (unbounded thread pool, with
+ * automatic thread reclamation), {@link Executors#newFixedThreadPool}
+ * (fixed size thread pool) and {@link
+ * Executors#newSingleThreadExecutor} (single background thread), that
+ * preconfigure settings for the most common usage
+ * scenarios. Otherwise, use the following guide when manually
+ * configuring and tuning this class:
+ *
+ * <dl>
+ *
+ * <dt>Core and maximum pool sizes</dt>
+ *
+ * <dd>A {@code ThreadPoolExecutor} will automatically adjust the
+ * pool size (see {@link #getPoolSize})
+ * according to the bounds set by
+ * corePoolSize (see {@link #getCorePoolSize}) and
+ * maximumPoolSize (see {@link #getMaximumPoolSize}).
+ *
+ * When a new task is submitted in method {@link #execute(Runnable)},
+ * if fewer than corePoolSize threads are running, a new thread is
+ * created to handle the request, even if other worker threads are
+ * idle.  Else if fewer than maximumPoolSize threads are running, a
+ * new thread will be created to handle the request only if the queue
+ * is full.  By setting corePoolSize and maximumPoolSize the same, you
+ * create a fixed-size thread pool. By setting maximumPoolSize to an
+ * essentially unbounded value such as {@code Integer.MAX_VALUE}, you
+ * allow the pool to accommodate an arbitrary number of concurrent
+ * tasks. Most typically, core and maximum pool sizes are set only
+ * upon construction, but they may also be changed dynamically using
+ * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd>
+ *
+ * <dt>On-demand construction</dt>
+ *
+ * <dd>By default, even core threads are initially created and
+ * started only when new tasks arrive, but this can be overridden
+ * dynamically using method {@link #prestartCoreThread} or {@link
+ * #prestartAllCoreThreads}.  You probably want to prestart threads if
+ * you construct the pool with a non-empty queue. </dd>
+ *
+ * <dt>Creating new threads</dt>
+ *
+ * <dd>New threads are created using a {@link ThreadFactory}.  If not
+ * otherwise specified, a {@link Executors#defaultThreadFactory} is
+ * used, that creates threads to all be in the same {@link
+ * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
+ * non-daemon status. By supplying a different ThreadFactory, you can
+ * alter the thread's name, thread group, priority, daemon status,
+ * etc. If a {@code ThreadFactory} fails to create a thread when asked
+ * by returning null from {@code newThread}, the executor will
+ * continue, but might not be able to execute any tasks. Threads
+ * should possess the "modifyThread" {@code RuntimePermission}. If
+ * worker threads or other threads using the pool do not possess this
+ * permission, service may be degraded: configuration changes may not
+ * take effect in a timely manner, and a shutdown pool may remain in a
+ * state in which termination is possible but not completed.</dd>
+ *
+ * <dt>Keep-alive times</dt>
+ *
+ * <dd>If the pool currently has more than corePoolSize threads,
+ * excess threads will be terminated if they have been idle for more
+ * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
+ * This provides a means of reducing resource consumption when the
+ * pool is not being actively used. If the pool becomes more active
+ * later, new threads will be constructed. This parameter can also be
+ * changed dynamically using method {@link #setKeepAliveTime(long,
+ * TimeUnit)}.  Using a value of {@code Long.MAX_VALUE} {@link
+ * TimeUnit#NANOSECONDS} effectively disables idle threads from ever
+ * terminating prior to shut down. By default, the keep-alive policy
+ * applies only when there are more than corePoolSize threads, but
+ * method {@link #allowCoreThreadTimeOut(boolean)} can be used to
+ * apply this time-out policy to core threads as well, so long as the
+ * keepAliveTime value is non-zero. </dd>
+ *
+ * <dt>Queuing</dt>
+ *
+ * <dd>Any {@link BlockingQueue} may be used to transfer and hold
+ * submitted tasks.  The use of this queue interacts with pool sizing:
+ *
+ * <ul>
+ *
+ * <li>If fewer than corePoolSize threads are running, the Executor
+ * always prefers adding a new thread
+ * rather than queuing.
+ *
+ * <li>If corePoolSize or more threads are running, the Executor
+ * always prefers queuing a request rather than adding a new
+ * thread.
+ *
+ * <li>If a request cannot be queued, a new thread is created unless
+ * this would exceed maximumPoolSize, in which case, the task will be
+ * rejected.
+ *
+ * </ul>
+ *
+ * There are three general strategies for queuing:
+ * <ol>
+ *
+ * <li><em> Direct handoffs.</em> A good default choice for a work
+ * queue is a {@link SynchronousQueue} that hands off tasks to threads
+ * without otherwise holding them. Here, an attempt to queue a task
+ * will fail if no threads are immediately available to run it, so a
+ * new thread will be constructed. This policy avoids lockups when
+ * handling sets of requests that might have internal dependencies.
+ * Direct handoffs generally require unbounded maximumPoolSizes to
+ * avoid rejection of new submitted tasks. This in turn admits the
+ * possibility of unbounded thread growth when commands continue to
+ * arrive on average faster than they can be processed.
+ *
+ * <li><em> Unbounded queues.</em> Using an unbounded queue (for
+ * example a {@link LinkedBlockingQueue} without a predefined
+ * capacity) will cause new tasks to wait in the queue when all
+ * corePoolSize threads are busy. Thus, no more than corePoolSize
+ * threads will ever be created. (And the value of the maximumPoolSize
+ * therefore doesn't have any effect.)  This may be appropriate when
+ * each task is completely independent of others, so tasks cannot
+ * affect each others execution; for example, in a web page server.
+ * While this style of queuing can be useful in smoothing out
+ * transient bursts of requests, it admits the possibility of
+ * unbounded work queue growth when commands continue to arrive on
+ * average faster than they can be processed.
+ *
+ * <li><em>Bounded queues.</em> A bounded queue (for example, an
+ * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
+ * used with finite maximumPoolSizes, but can be more difficult to
+ * tune and control.  Queue sizes and maximum pool sizes may be traded
+ * off for each other: Using large queues and small pools minimizes
+ * CPU usage, OS resources, and context-switching overhead, but can
+ * lead to artificially low throughput.  If tasks frequently block (for
+ * example if they are I/O bound), a system may be able to schedule
+ * time for more threads than you otherwise allow. Use of small queues
+ * generally requires larger pool sizes, which keeps CPUs busier but
+ * may encounter unacceptable scheduling overhead, which also
+ * decreases throughput.
+ *
+ * </ol>
+ *
+ * </dd>
+ *
+ * <dt>Rejected tasks</dt>
+ *
+ * <dd>New tasks submitted in method {@link #execute(Runnable)} will be
+ * <em>rejected</em> when the Executor has been shut down, and also when
+ * the Executor uses finite bounds for both maximum threads and work queue
+ * capacity, and is saturated.  In either case, the {@code execute} method
+ * invokes the {@link
+ * RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}
+ * method of its {@link RejectedExecutionHandler}.  Four predefined handler
+ * policies are provided:
+ *
+ * <ol>
+ *
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the handler
+ * throws a runtime {@link RejectedExecutionException} upon rejection.
+ *
+ * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
+ * that invokes {@code execute} itself runs the task. This provides a
+ * simple feedback control mechanism that will slow down the rate that
+ * new tasks are submitted.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that cannot
+ * be executed is simply dropped. This policy is designed only for
+ * those rare cases in which task completion is never relied upon.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
+ * executor is not shut down, the task at the head of the work queue
+ * is dropped, and then execution is retried (which can fail again,
+ * causing this to be repeated.) This policy is rarely acceptable.  In
+ * nearly all cases, you should also cancel the task to cause an
+ * exception in any component waiting for its completion, and/or log
+ * the failure, as illustrated in {@link
+ * ThreadPoolExecutor.DiscardOldestPolicy} documentation.
+ *
+ * </ol>
+ *
+ * It is possible to define and use other kinds of {@link
+ * RejectedExecutionHandler} classes. Doing so requires some care
+ * especially when policies are designed to work only under particular
+ * capacity or queuing policies. </dd>
+ *
+ * <dt>Hook methods</dt>
+ *
+ * <dd>This class provides {@code protected} overridable
+ * {@link #beforeExecute(Thread, Runnable)} and
+ * {@link #afterExecute(Runnable, Throwable)} methods that are called
+ * before and after execution of each task.  These can be used to
+ * manipulate the execution environment; for example, reinitializing
+ * ThreadLocals, gathering statistics, or adding log entries.
+ * Additionally, method {@link #terminated} can be overridden to perform
+ * any special processing that needs to be done once the Executor has
+ * fully terminated.
+ *
+ * <p>If hook, callback, or BlockingQueue methods throw exceptions,
+ * internal worker threads may in turn fail, abruptly terminate, and
+ * possibly be replaced.</dd>
+ *
+ * <dt>Queue maintenance</dt>
+ *
+ * <dd>Method {@link #getQueue()} allows access to the work queue
+ * for purposes of monitoring and debugging.  Use of this method for
+ * any other purpose is strongly discouraged.  Two supplied methods,
+ * {@link #remove(Runnable)} and {@link #purge} are available to
+ * assist in storage reclamation when large numbers of queued tasks
+ * become cancelled.</dd>
+ *
+ * <dt>Reclamation</dt>
+ *
+ * <dd>A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads may be reclaimed (garbage collected)
+ * without being explicitly shutdown. You can configure a pool to
+ * allow all unused threads to eventually die by setting appropriate
+ * keep-alive times, using a lower bound of zero core threads and/or
+ * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd>
+ *
+ * </dl>
+ *
+ * <p><b>Extension example.</b> Most extensions of this class
+ * override one or more of the protected hook methods. For example,
+ * here is a subclass that adds a simple pause/resume feature:
+ *
+ * <pre> {@code
+ * class PausableThreadPoolExecutor extends ThreadPoolExecutor {
+ *   private boolean isPaused;
+ *   private ReentrantLock pauseLock = new ReentrantLock();
+ *   private Condition unpaused = pauseLock.newCondition();
+ *
+ *   public PausableThreadPoolExecutor(...) { super(...); }
+ *
+ *   protected void beforeExecute(Thread t, Runnable r) {
+ *     super.beforeExecute(t, r);
+ *     pauseLock.lock();
+ *     try {
+ *       while (isPaused) unpaused.await();
+ *     } catch (InterruptedException ie) {
+ *       t.interrupt();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void pause() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = true;
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void resume() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = false;
+ *       unpaused.signalAll();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ThreadPoolExecutor extends AbstractExecutorService {
+    /**
+     * The main pool control state, ctl, is an atomic integer packing
+     * two conceptual fields
+     *   workerCount, indicating the effective number of threads
+     *   runState,    indicating whether running, shutting down etc
+     *
+     * In order to pack them into one int, we limit workerCount to
+     * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
+     * billion) otherwise representable. If this is ever an issue in
+     * the future, the variable can be changed to be an AtomicLong,
+     * and the shift/mask constants below adjusted. But until the need
+     * arises, this code is a bit faster and simpler using an int.
+     *
+     * The workerCount is the number of workers that have been
+     * permitted to start and not permitted to stop.  The value may be
+     * transiently different from the actual number of live threads,
+     * for example when a ThreadFactory fails to create a thread when
+     * asked, and when exiting threads are still performing
+     * bookkeeping before terminating. The user-visible pool size is
+     * reported as the current size of the workers set.
+     *
+     * The runState provides the main lifecycle control, taking on values:
+     *
+     *   RUNNING:  Accept new tasks and process queued tasks
+     *   SHUTDOWN: Don't accept new tasks, but process queued tasks
+     *   STOP:     Don't accept new tasks, don't process queued tasks,
+     *             and interrupt in-progress tasks
+     *   TIDYING:  All tasks have terminated, workerCount is zero,
+     *             the thread transitioning to state TIDYING
+     *             will run the terminated() hook method
+     *   TERMINATED: terminated() has completed
+     *
+     * The numerical order among these values matters, to allow
+     * ordered comparisons. The runState monotonically increases over
+     * time, but need not hit each state. The transitions are:
+     *
+     * RUNNING -> SHUTDOWN
+     *    On invocation of shutdown()
+     * (RUNNING or SHUTDOWN) -> STOP
+     *    On invocation of shutdownNow()
+     * SHUTDOWN -> TIDYING
+     *    When both queue and pool are empty
+     * STOP -> TIDYING
+     *    When pool is empty
+     * TIDYING -> TERMINATED
+     *    When the terminated() hook method has completed
+     *
+     * Threads waiting in awaitTermination() will return when the
+     * state reaches TERMINATED.
+     *
+     * Detecting the transition from SHUTDOWN to TIDYING is less
+     * straightforward than you'd like because the queue may become
+     * empty after non-empty and vice versa during SHUTDOWN state, but
+     * we can only terminate if, after seeing that it is empty, we see
+     * that workerCount is 0 (which sometimes entails a recheck -- see
+     * below).
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
+    private static final int COUNT_BITS = Integer.SIZE - 3;
+    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
+
+    // runState is stored in the high-order bits
+    private static final int RUNNING    = -1 << COUNT_BITS;
+    private static final int SHUTDOWN   =  0 << COUNT_BITS;
+    private static final int STOP       =  1 << COUNT_BITS;
+    private static final int TIDYING    =  2 << COUNT_BITS;
+    private static final int TERMINATED =  3 << COUNT_BITS;
+
+    // Packing and unpacking ctl
+    private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
+    private static int workerCountOf(int c)  { return c & COUNT_MASK; }
+    private static int ctlOf(int rs, int wc) { return rs | wc; }
+
+    /*
+     * Bit field accessors that don't require unpacking ctl.
+     * These depend on the bit layout and on workerCount being never negative.
+     */
+
+    private static boolean runStateLessThan(int c, int s) {
+        return c < s;
+    }
+
+    private static boolean runStateAtLeast(int c, int s) {
+        return c >= s;
+    }
+
+    private static boolean isRunning(int c) {
+        return c < SHUTDOWN;
+    }
+
+    /**
+     * Attempts to CAS-increment the workerCount field of ctl.
+     */
+    private boolean compareAndIncrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect + 1);
+    }
+
+    /**
+     * Attempts to CAS-decrement the workerCount field of ctl.
+     */
+    private boolean compareAndDecrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect - 1);
+    }
+
+    /**
+     * Decrements the workerCount field of ctl. This is called only on
+     * abrupt termination of a thread (see processWorkerExit). Other
+     * decrements are performed within getTask.
+     */
+    private void decrementWorkerCount() {
+        ctl.addAndGet(-1);
+    }
+
+    /**
+     * The queue used for holding tasks and handing off to worker
+     * threads.  We do not require that workQueue.poll() returning
+     * null necessarily means that workQueue.isEmpty(), so rely
+     * solely on isEmpty to see if the queue is empty (which we must
+     * do for example when deciding whether to transition from
+     * SHUTDOWN to TIDYING).  This accommodates special-purpose
+     * queues such as DelayQueues for which poll() is allowed to
+     * return null even if it may later return non-null when delays
+     * expire.
+     */
+    private final BlockingQueue<Runnable> workQueue;
+
+    /**
+     * Lock held on access to workers set and related bookkeeping.
+     * While we could use a concurrent set of some sort, it turns out
+     * to be generally preferable to use a lock. Among the reasons is
+     * that this serializes interruptIdleWorkers, which avoids
+     * unnecessary interrupt storms, especially during shutdown.
+     * Otherwise exiting threads would concurrently interrupt those
+     * that have not yet interrupted. It also simplifies some of the
+     * associated statistics bookkeeping of largestPoolSize etc. We
+     * also hold mainLock on shutdown and shutdownNow, for the sake of
+     * ensuring workers set is stable while separately checking
+     * permission to interrupt and actually interrupting.
+     */
+    private final ReentrantLock mainLock = new ReentrantLock();
+
+    /**
+     * Set containing all worker threads in pool. Accessed only when
+     * holding mainLock.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final HashSet<Worker> workers = new HashSet<>();
+
+    /**
+     * Wait condition to support awaitTermination.
+     */
+    private final Condition termination = mainLock.newCondition();
+
+    /**
+     * Tracks largest attained pool size. Accessed only under
+     * mainLock.
+     */
+    private int largestPoolSize;
+
+    /**
+     * Counter for completed tasks. Updated only on termination of
+     * worker threads. Accessed only under mainLock.
+     */
+    private long completedTaskCount;
+
+    /*
+     * All user control parameters are declared as volatiles so that
+     * ongoing actions are based on freshest values, but without need
+     * for locking, since no internal invariants depend on them
+     * changing synchronously with respect to other actions.
+     */
+
+    /**
+     * Factory for new threads. All threads are created using this
+     * factory (via method addWorker).  All callers must be prepared
+     * for addWorker to fail, which may reflect a system or user's
+     * policy limiting the number of threads.  Even though it is not
+     * treated as an error, failure to create threads may result in
+     * new tasks being rejected or existing ones remaining stuck in
+     * the queue.
+     *
+     * We go further and preserve pool invariants even in the face of
+     * errors such as OutOfMemoryError, that might be thrown while
+     * trying to create threads.  Such errors are rather common due to
+     * the need to allocate a native stack in Thread.start, and users
+     * will want to perform clean pool shutdown to clean up.  There
+     * will likely be enough memory available for the cleanup code to
+     * complete without encountering yet another OutOfMemoryError.
+     */
+    private volatile ThreadFactory threadFactory;
+
+    /**
+     * Handler called when saturated or shutdown in execute.
+     */
+    private volatile RejectedExecutionHandler handler;
+
+    /**
+     * Timeout in nanoseconds for idle threads waiting for work.
+     * Threads use this timeout when there are more than corePoolSize
+     * present or if allowCoreThreadTimeOut. Otherwise they wait
+     * forever for new work.
+     */
+    private volatile long keepAliveTime;
+
+    /**
+     * If false (default), core threads stay alive even when idle.
+     * If true, core threads use keepAliveTime to time out waiting
+     * for work.
+     */
+    private volatile boolean allowCoreThreadTimeOut;
+
+    /**
+     * Core pool size is the minimum number of workers to keep alive
+     * (and not allow to time out etc) unless allowCoreThreadTimeOut
+     * is set, in which case the minimum is zero.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code corePoolSize & COUNT_MASK}.
+     */
+    private volatile int corePoolSize;
+
+    /**
+     * Maximum pool size.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
+     */
+    private volatile int maximumPoolSize;
+
+    /**
+     * The default rejected execution handler.
+     */
+    private static final RejectedExecutionHandler defaultHandler =
+        new AbortPolicy();
+
+    /**
+     * Permission required for callers of shutdown and shutdownNow.
+     * We additionally require (see checkShutdownAccess) that callers
+     * have permission to actually interrupt threads in the worker set
+     * (as governed by Thread.interrupt, which relies on
+     * ThreadGroup.checkAccess, which in turn relies on
+     * SecurityManager.checkAccess). Shutdowns are attempted only if
+     * these checks pass.
+     *
+     * All actual invocations of Thread.interrupt (see
+     * interruptIdleWorkers and interruptWorkers) ignore
+     * SecurityExceptions, meaning that the attempted interrupts
+     * silently fail. In the case of shutdown, they should not fail
+     * unless the SecurityManager has inconsistent policies, sometimes
+     * allowing access to a thread and sometimes not. In such cases,
+     * failure to actually interrupt threads may disable or delay full
+     * termination. Other uses of interruptIdleWorkers are advisory,
+     * and failure to actually interrupt will merely delay response to
+     * configuration changes so is not handled exceptionally.
+     */
+    private static final RuntimePermission shutdownPerm =
+        new RuntimePermission("modifyThread");
+
+    /**
+     * Class Worker mainly maintains interrupt control state for
+     * threads running tasks, along with other minor bookkeeping.
+     * This class opportunistically extends AbstractQueuedSynchronizer
+     * to simplify acquiring and releasing a lock surrounding each
+     * task execution.  This protects against interrupts that are
+     * intended to wake up a worker thread waiting for a task from
+     * instead interrupting a task being run.  We implement a simple
+     * non-reentrant mutual exclusion lock rather than use
+     * ReentrantLock because we do not want worker tasks to be able to
+     * reacquire the lock when they invoke pool control methods like
+     * setCorePoolSize.  Additionally, to suppress interrupts until
+     * the thread actually starts running tasks, we initialize lock
+     * state to a negative value, and clear it upon start (in
+     * runWorker).
+     */
+    private final class Worker
+        extends AbstractQueuedSynchronizer
+        implements Runnable
+    {
+        /**
+         * This class will never be serialized, but we provide a
+         * serialVersionUID to suppress a javac warning.
+         */
+        private static final long serialVersionUID = 6138294804551838833L;
+
+        /** Thread this worker is running in.  Null if factory fails. */
+        @SuppressWarnings("serial") // Unlikely to be serializable
+        final Thread thread;
+        /** Initial task to run.  Possibly null. */
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        Runnable firstTask;
+        /** Per-thread task counter */
+        volatile long completedTasks;
+
+        // TODO: switch to AbstractQueuedLongSynchronizer and move
+        // completedTasks into the lock word.
+
+        /**
+         * Creates with given first task and thread from ThreadFactory.
+         * @param firstTask the first task (null if none)
+         */
+        Worker(Runnable firstTask) {
+            setState(-1); // inhibit interrupts until runWorker
+            this.firstTask = firstTask;
+            this.thread = getThreadFactory().newThread(this);
+        }
+
+        /** Delegates main run loop to outer runWorker. */
+        public void run() {
+            runWorker(this);
+        }
+
+        // Lock methods
+        //
+        // The value 0 represents the unlocked state.
+        // The value 1 represents the locked state.
+
+        protected boolean isHeldExclusively() {
+            return getState() != 0;
+        }
+
+        protected boolean tryAcquire(int unused) {
+            if (compareAndSetState(0, 1)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
+        }
+
+        protected boolean tryRelease(int unused) {
+            setExclusiveOwnerThread(null);
+            setState(0);
+            return true;
+        }
+
+        public void lock()        { acquire(1); }
+        public boolean tryLock()  { return tryAcquire(1); }
+        public void unlock()      { release(1); }
+        public boolean isLocked() { return isHeldExclusively(); }
+
+        void interruptIfStarted() {
+            Thread t;
+            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
+                try {
+                    t.interrupt();
+                } catch (SecurityException ignore) {
+                }
+            }
+        }
+    }
+
+    /*
+     * Methods for setting control state
+     */
+
+    /**
+     * Transitions runState to given target, or leaves it alone if
+     * already at least the given target.
+     *
+     * @param targetState the desired state, either SHUTDOWN or STOP
+     *        (but not TIDYING or TERMINATED -- use tryTerminate for that)
+     */
+    private void advanceRunState(int targetState) {
+        // assert targetState == SHUTDOWN || targetState == STOP;
+        for (;;) {
+            int c = ctl.get();
+            if (runStateAtLeast(c, targetState) ||
+                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
+                break;
+        }
+    }
+
+    /**
+     * Transitions to TERMINATED state if either (SHUTDOWN and pool
+     * and queue empty) or (STOP and pool empty).  If otherwise
+     * eligible to terminate but workerCount is nonzero, interrupts an
+     * idle worker to ensure that shutdown signals propagate. This
+     * method must be called following any action that might make
+     * termination possible -- reducing worker count or removing tasks
+     * from the queue during shutdown. The method is non-private to
+     * allow access from ScheduledThreadPoolExecutor.
+     */
+    final void tryTerminate() {
+        for (;;) {
+            int c = ctl.get();
+            if (isRunning(c) ||
+                runStateAtLeast(c, TIDYING) ||
+                (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
+                return;
+            if (workerCountOf(c) != 0) { // Eligible to terminate
+                interruptIdleWorkers(ONLY_ONE);
+                return;
+            }
+
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+                    try {
+                        terminated();
+                    } finally {
+                        ctl.set(ctlOf(TERMINATED, 0));
+                        termination.signalAll();
+                    }
+                    return;
+                }
+            } finally {
+                mainLock.unlock();
+            }
+            // else retry on failed CAS
+        }
+    }
+
+    /*
+     * Methods for controlling interrupts to worker threads.
+     */
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to shut down threads in general (see shutdownPerm).
+     * If this passes, additionally makes sure the caller is allowed
+     * to interrupt each worker thread. This might not be true even if
+     * first check passed, if the SecurityManager treats some threads
+     * specially.
+     */
+    private void checkShutdownAccess() {
+        // assert mainLock.isHeldByCurrentThread();
+        @SuppressWarnings("removal")
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(shutdownPerm);
+            for (Worker w : workers)
+                security.checkAccess(w.thread);
+        }
+    }
+
+    /**
+     * Interrupts all threads, even if active. Ignores SecurityExceptions
+     * (in which case some threads may remain uninterrupted).
+     */
+    private void interruptWorkers() {
+        // assert mainLock.isHeldByCurrentThread();
+        for (Worker w : workers)
+            w.interruptIfStarted();
+    }
+
+    /**
+     * Interrupts threads that might be waiting for tasks (as
+     * indicated by not being locked) so they can check for
+     * termination or configuration changes. Ignores
+     * SecurityExceptions (in which case some threads may remain
+     * uninterrupted).
+     *
+     * @param onlyOne If true, interrupt at most one worker. This is
+     * called only from tryTerminate when termination is otherwise
+     * enabled but there are still other workers.  In this case, at
+     * most one waiting worker is interrupted to propagate shutdown
+     * signals in case all threads are currently waiting.
+     * Interrupting any arbitrary thread ensures that newly arriving
+     * workers since shutdown began will also eventually exit.
+     * To guarantee eventual termination, it suffices to always
+     * interrupt only one idle worker, but shutdown() interrupts all
+     * idle workers so that redundant workers exit promptly, not
+     * waiting for a straggler task to finish.
+     */
+    private void interruptIdleWorkers(boolean onlyOne) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers) {
+                Thread t = w.thread;
+                if (!t.isInterrupted() && w.tryLock()) {
+                    try {
+                        t.interrupt();
+                    } catch (SecurityException ignore) {
+                    } finally {
+                        w.unlock();
+                    }
+                }
+                if (onlyOne)
+                    break;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Common form of interruptIdleWorkers, to avoid having to
+     * remember what the boolean argument means.
+     */
+    private void interruptIdleWorkers() {
+        interruptIdleWorkers(false);
+    }
+
+    private static final boolean ONLY_ONE = true;
+
+    /*
+     * Misc utilities, most of which are also exported to
+     * ScheduledThreadPoolExecutor
+     */
+
+    /**
+     * Invokes the rejected execution handler for the given command.
+     * Package-protected for use by ScheduledThreadPoolExecutor.
+     */
+    final void reject(Runnable command) {
+        handler.rejectedExecution(command, this);
+    }
+
+    /**
+     * Performs any further cleanup following run state transition on
+     * invocation of shutdown.  A no-op here, but used by
+     * ScheduledThreadPoolExecutor to cancel delayed tasks.
+     */
+    void onShutdown() {
+    }
+
+    /**
+     * Drains the task queue into a new list, normally using
+     * drainTo. But if the queue is a DelayQueue or any other kind of
+     * queue for which poll or drainTo may fail to remove some
+     * elements, it deletes them one by one.
+     */
+    private List<Runnable> drainQueue() {
+        BlockingQueue<Runnable> q = workQueue;
+        ArrayList<Runnable> taskList = new ArrayList<>();
+        q.drainTo(taskList);
+        if (!q.isEmpty()) {
+            for (Runnable r : q.toArray(new Runnable[0])) {
+                if (q.remove(r))
+                    taskList.add(r);
+            }
+        }
+        return taskList;
+    }
+
+    /*
+     * Methods for creating, running and cleaning up after workers
+     */
+
+    /**
+     * Checks if a new worker can be added with respect to current
+     * pool state and the given bound (either core or maximum). If so,
+     * the worker count is adjusted accordingly, and, if possible, a
+     * new worker is created and started, running firstTask as its
+     * first task. This method returns false if the pool is stopped or
+     * eligible to shut down. It also returns false if the thread
+     * factory fails to create a thread when asked.  If the thread
+     * creation fails, either due to the thread factory returning
+     * null, or due to an exception (typically OutOfMemoryError in
+     * Thread.start()), we roll back cleanly.
+     *
+     * @param firstTask the task the new thread should run first (or
+     * null if none). Workers are created with an initial first task
+     * (in method execute()) to bypass queuing when there are fewer
+     * than corePoolSize threads (in which case we always start one),
+     * or when the queue is full (in which case we must bypass queue).
+     * Initially idle threads are usually created via
+     * prestartCoreThread or to replace other dying workers.
+     *
+     * @param core if true use corePoolSize as bound, else
+     * maximumPoolSize. (A boolean indicator is used here rather than a
+     * value to ensure reads of fresh values after checking other pool
+     * state).
+     * @return true if successful
+     */
+    private boolean addWorker(Runnable firstTask, boolean core) {
+        retry:
+        for (int c = ctl.get();;) {
+            // Check if queue empty only if necessary.
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP)
+                    || firstTask != null
+                    || workQueue.isEmpty()))
+                return false;
+
+            for (;;) {
+                if (workerCountOf(c)
+                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
+                    return false;
+                if (compareAndIncrementWorkerCount(c))
+                    break retry;
+                c = ctl.get();  // Re-read ctl
+                if (runStateAtLeast(c, SHUTDOWN))
+                    continue retry;
+                // else CAS failed due to workerCount change; retry inner loop
+            }
+        }
+
+        boolean workerStarted = false;
+        boolean workerAdded = false;
+        Worker w = null;
+        try {
+            w = new Worker(firstTask);
+            final Thread t = w.thread;
+            if (t != null) {
+                final ReentrantLock mainLock = this.mainLock;
+                mainLock.lock();
+                try {
+                    // Recheck while holding lock.
+                    // Back out on ThreadFactory failure or if
+                    // shut down before lock acquired.
+                    int c = ctl.get();
+
+                    if (isRunning(c) ||
+                        (runStateLessThan(c, STOP) && firstTask == null)) {
+                        if (t.getState() != Thread.State.NEW)
+                            throw new IllegalThreadStateException();
+                        workers.add(w);
+                        workerAdded = true;
+                        int s = workers.size();
+                        if (s > largestPoolSize)
+                            largestPoolSize = s;
+                    }
+                } finally {
+                    mainLock.unlock();
+                }
+                if (workerAdded) {
+                    t.start();
+                    workerStarted = true;
+                }
+            }
+        } finally {
+            if (! workerStarted)
+                addWorkerFailed(w);
+        }
+        return workerStarted;
+    }
+
+    /**
+     * Rolls back the worker thread creation.
+     * - removes worker from workers, if present
+     * - decrements worker count
+     * - rechecks for termination, in case the existence of this
+     *   worker was holding up termination
+     */
+    private void addWorkerFailed(Worker w) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            if (w != null)
+                workers.remove(w);
+            decrementWorkerCount();
+            tryTerminate();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Performs cleanup and bookkeeping for a dying worker. Called
+     * only from worker threads. Unless completedAbruptly is set,
+     * assumes that workerCount has already been adjusted to account
+     * for exit.  This method removes thread from worker set, and
+     * possibly terminates the pool or replaces the worker if either
+     * it exited due to user task exception or if fewer than
+     * corePoolSize workers are running or queue is non-empty but
+     * there are no workers.
+     *
+     * @param w the worker
+     * @param completedAbruptly if the worker died due to user exception
+     */
+    private void processWorkerExit(Worker w, boolean completedAbruptly) {
+        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
+            decrementWorkerCount();
+
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            completedTaskCount += w.completedTasks;
+            workers.remove(w);
+        } finally {
+            mainLock.unlock();
+        }
+
+        tryTerminate();
+
+        int c = ctl.get();
+        if (runStateLessThan(c, STOP)) {
+            if (!completedAbruptly) {
+                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+                if (min == 0 && ! workQueue.isEmpty())
+                    min = 1;
+                if (workerCountOf(c) >= min)
+                    return; // replacement not needed
+            }
+            addWorker(null, false);
+        }
+    }
+
+    /**
+     * Performs blocking or timed wait for a task, depending on
+     * current configuration settings, or returns null if this worker
+     * must exit because of any of:
+     * 1. There are more than maximumPoolSize workers (due to
+     *    a call to setMaximumPoolSize).
+     * 2. The pool is stopped.
+     * 3. The pool is shutdown and the queue is empty.
+     * 4. This worker timed out waiting for a task, and timed-out
+     *    workers are subject to termination (that is,
+     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
+     *    both before and after the timed wait, and if the queue is
+     *    non-empty, this worker is not the last thread in the pool.
+     *
+     * @return task, or null if the worker must exit, in which case
+     *         workerCount is decremented
+     */
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+
+            // Check if queue empty only if necessary.
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+
+    /**
+     * Main worker run loop.  Repeatedly gets tasks from queue and
+     * executes them, while coping with a number of issues:
+     *
+     * 1. We may start out with an initial task, in which case we
+     * don't need to get the first one. Otherwise, as long as pool is
+     * running, we get tasks from getTask. If it returns null then the
+     * worker exits due to changed pool state or configuration
+     * parameters.  Other exits result from exception throws in
+     * external code, in which case completedAbruptly holds, which
+     * usually leads processWorkerExit to replace this thread.
+     *
+     * 2. Before running any task, the lock is acquired to prevent
+     * other pool interrupts while the task is executing, and then we
+     * ensure that unless pool is stopping, this thread does not have
+     * its interrupt set.
+     *
+     * 3. Each task run is preceded by a call to beforeExecute, which
+     * might throw an exception, in which case we cause thread to die
+     * (breaking loop with completedAbruptly true) without processing
+     * the task.
+     *
+     * 4. Assuming beforeExecute completes normally, we run the task,
+     * gathering any of its thrown exceptions to send to afterExecute.
+     * We separately handle RuntimeException, Error (both of which the
+     * specs guarantee that we trap) and arbitrary Throwables.
+     * Because we cannot rethrow Throwables within Runnable.run, we
+     * wrap them within Errors on the way out (to the thread's
+     * UncaughtExceptionHandler).  Any thrown exception also
+     * conservatively causes thread to die.
+     *
+     * 5. After task.run completes, we call afterExecute, which may
+     * also throw an exception, which will also cause thread to
+     * die. According to JLS Sec 14.20, this exception is the one that
+     * will be in effect even if task.run throws.
+     *
+     * The net effect of the exception mechanics is that afterExecute
+     * and the thread's UncaughtExceptionHandler have as accurate
+     * information as we can provide about any problems encountered by
+     * user code.
+     *
+     * @param w the worker
+     */
+    final void runWorker(Worker w) {
+        Thread wt = Thread.currentThread();
+        Runnable task = w.firstTask;
+        w.firstTask = null;
+        w.unlock(); // allow interrupts
+        boolean completedAbruptly = true;
+        try {
+            while (task != null || (task = getTask()) != null) {
+                w.lock();
+                // If pool is stopping, ensure thread is interrupted;
+                // if not, ensure thread is not interrupted.  This
+                // requires a recheck in second case to deal with
+                // shutdownNow race while clearing interrupt
+                if ((runStateAtLeast(ctl.get(), STOP) ||
+                     (Thread.interrupted() &&
+                      runStateAtLeast(ctl.get(), STOP))) &&
+                    !wt.isInterrupted())
+                    wt.interrupt();
+                try {
+                    beforeExecute(wt, task);
+                    try {
+                        task.run();
+                        afterExecute(task, null);
+                    } catch (Throwable ex) {
+                        afterExecute(task, ex);
+                        throw ex;
+                    }
+                } finally {
+                    task = null;
+                    w.completedTasks++;
+                    w.unlock();
+                }
+            }
+            completedAbruptly = false;
+        } finally {
+            processWorkerExit(w, completedAbruptly);
+        }
+    }
+
+    // Public constructors and methods
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters, the
+     * {@linkplain Executors#defaultThreadFactory default thread factory}
+     * and the {@linkplain ThreadPoolExecutor.AbortPolicy
+     * default rejected execution handler}.
+     *
+     * <p>It may be more convenient to use one of the {@link Executors}
+     * factory methods instead of this general purpose constructor.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and the {@linkplain ThreadPoolExecutor.AbortPolicy
+     * default rejected execution handler}.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             threadFactory, defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and the
+     * {@linkplain Executors#defaultThreadFactory default thread factory}.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              RejectedExecutionHandler handler) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), handler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory,
+                              RejectedExecutionHandler handler) {
+        if (corePoolSize < 0 ||
+            maximumPoolSize <= 0 ||
+            maximumPoolSize < corePoolSize ||
+            keepAliveTime < 0)
+            throw new IllegalArgumentException();
+        if (workQueue == null || threadFactory == null || handler == null)
+            throw new NullPointerException();
+        this.corePoolSize = corePoolSize;
+        this.maximumPoolSize = maximumPoolSize;
+        this.workQueue = workQueue;
+        this.keepAliveTime = unit.toNanos(keepAliveTime);
+        this.threadFactory = threadFactory;
+        this.handler = handler;
+    }
+
+    /**
+     * Executes the given task sometime in the future.  The task
+     * may execute in a new thread or in an existing pooled thread.
+     *
+     * If the task cannot be submitted for execution, either because this
+     * executor has been shutdown or because its capacity has been reached,
+     * the task is handled by the current {@link RejectedExecutionHandler}.
+     *
+     * @param command the task to execute
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution
+     * @throws NullPointerException if {@code command} is null
+     */
+    public void execute(Runnable command) {
+        if (command == null)
+            throw new NullPointerException();
+        /*
+         * Proceed in 3 steps:
+         *
+         * 1. If fewer than corePoolSize threads are running, try to
+         * start a new thread with the given command as its first
+         * task.  The call to addWorker atomically checks runState and
+         * workerCount, and so prevents false alarms that would add
+         * threads when it shouldn't, by returning false.
+         *
+         * 2. If a task can be successfully queued, then we still need
+         * to double-check whether we should have added a thread
+         * (because existing ones died since last checking) or that
+         * the pool shut down since entry into this method. So we
+         * recheck state and if necessary roll back the enqueuing if
+         * stopped, or start a new thread if there are none.
+         *
+         * 3. If we cannot queue task, then we try to add a new
+         * thread.  If it fails, we know we are shut down or saturated
+         * and so reject the task.
+         */
+        int c = ctl.get();
+        if (workerCountOf(c) < corePoolSize) {
+            if (addWorker(command, true))
+                return;
+            c = ctl.get();
+        }
+        if (isRunning(c) && workQueue.offer(command)) {
+            int recheck = ctl.get();
+            if (! isRunning(recheck) && remove(command))
+                reject(command);
+            else if (workerCountOf(recheck) == 0)
+                addWorker(null, false);
+        }
+        else if (!addWorker(command, false))
+            reject(command);
+    }
+
+    /**
+     * 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.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    // android-note: Removed @throws SecurityException
+    public void shutdown() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(SHUTDOWN);
+            interruptIdleWorkers();
+            onShutdown(); // hook for ScheduledThreadPoolExecutor
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     */
+    // android-note: Removed @throws SecurityException
+    public List<Runnable> shutdownNow() {
+        List<Runnable> tasks;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(STOP);
+            interruptWorkers();
+            tasks = drainQueue();
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+        return tasks;
+    }
+
+    public boolean isShutdown() {
+        return runStateAtLeast(ctl.get(), SHUTDOWN);
+    }
+
+    /** Used by ScheduledThreadPoolExecutor. */
+    boolean isStopped() {
+        return runStateAtLeast(ctl.get(), STOP);
+    }
+
+    /**
+     * Returns true if this executor is in the process of terminating
+     * after {@link #shutdown} or {@link #shutdownNow} but has not
+     * completely terminated.  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, causing this executor not
+     * to properly terminate.
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        int c = ctl.get();
+        return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
+    }
+
+    public boolean isTerminated() {
+        return runStateAtLeast(ctl.get(), TERMINATED);
+    }
+
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            while (runStateLessThan(ctl.get(), TERMINATED)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = termination.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    // Override without "throws Throwable" for compatibility with subclasses
+    // whose finalize method invokes super.finalize() (as is recommended).
+    // Before JDK 11, finalize() had a non-empty method body.
+
+    // Android-added: The @deprecated javadoc tag
+    /**
+     * @implNote Previous versions of this class had a finalize method
+     * that shut down this executor, but in this version, finalize
+     * does nothing.
+     *
+     * @deprecated Subclass is not recommended to override finalize(). If it
+     * must, please always invoke super.finalize().
+     */
+    @Deprecated(since="9")
+    protected void finalize() {}
+
+    /**
+     * Sets the thread factory used to create new threads.
+     *
+     * @param threadFactory the new thread factory
+     * @throws NullPointerException if threadFactory is null
+     * @see #getThreadFactory
+     */
+    public void setThreadFactory(ThreadFactory threadFactory) {
+        if (threadFactory == null)
+            throw new NullPointerException();
+        this.threadFactory = threadFactory;
+    }
+
+    /**
+     * Returns the thread factory used to create new threads.
+     *
+     * @return the current thread factory
+     * @see #setThreadFactory(ThreadFactory)
+     */
+    public ThreadFactory getThreadFactory() {
+        return threadFactory;
+    }
+
+    /**
+     * Sets a new handler for unexecutable tasks.
+     *
+     * @param handler the new handler
+     * @throws NullPointerException if handler is null
+     * @see #getRejectedExecutionHandler
+     */
+    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
+        if (handler == null)
+            throw new NullPointerException();
+        this.handler = handler;
+    }
+
+    /**
+     * Returns the current handler for unexecutable tasks.
+     *
+     * @return the current handler
+     * @see #setRejectedExecutionHandler(RejectedExecutionHandler)
+     */
+    public RejectedExecutionHandler getRejectedExecutionHandler() {
+        return handler;
+    }
+
+    // Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+    /**
+     * Sets the core number of threads.  This overrides any value set
+     * in the constructor.  If the new value is smaller than the
+     * current value, excess existing threads will be terminated when
+     * they next become idle.  If larger, new threads will, if needed,
+     * be started to execute any queued tasks.
+     *
+     * @param corePoolSize the new core size
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @see #getCorePoolSize
+     */
+    public void setCorePoolSize(int corePoolSize) {
+        // BEGIN Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+        // This reverts a change that threw an IAE on that condition. This is due to defective code
+        // in a commonly used third party library that does something like exec.setCorePoolSize(N)
+        // before doing exec.setMaxPoolSize(N).
+        //
+        // if (corePoolSize < 0 || maximumPoolSize < corePoolSize)
+        if (corePoolSize < 0)
+        // END Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+            throw new IllegalArgumentException();
+        int delta = corePoolSize - this.corePoolSize;
+        this.corePoolSize = corePoolSize;
+        if (workerCountOf(ctl.get()) > corePoolSize)
+            interruptIdleWorkers();
+        else if (delta > 0) {
+            // We don't really know how many new threads are "needed".
+            // As a heuristic, prestart enough new workers (up to new
+            // core size) to handle the current number of tasks in
+            // queue, but stop if queue becomes empty while doing so.
+            int k = Math.min(delta, workQueue.size());
+            while (k-- > 0 && addWorker(null, true)) {
+                if (workQueue.isEmpty())
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Returns the core number of threads.
+     *
+     * @return the core number of threads
+     * @see #setCorePoolSize
+     */
+    public int getCorePoolSize() {
+        return corePoolSize;
+    }
+
+    /**
+     * Starts a core thread, causing it to idly wait for work. This
+     * overrides the default policy of starting core threads only when
+     * new tasks are executed. This method will return {@code false}
+     * if all core threads have already been started.
+     *
+     * @return {@code true} if a thread was started
+     */
+    public boolean prestartCoreThread() {
+        return workerCountOf(ctl.get()) < corePoolSize &&
+            addWorker(null, true);
+    }
+
+    /**
+     * 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.
+     *
+     * @return the number of threads started
+     */
+    public int prestartAllCoreThreads() {
+        int n = 0;
+        while (addWorker(null, true))
+            ++n;
+        return n;
+    }
+
+    /**
+     * Returns true if this pool allows core threads to time out and
+     * terminate if no tasks arrive within the keepAlive time, being
+     * replaced if needed when new tasks arrive. When true, the same
+     * keep-alive policy applying to non-core threads applies also to
+     * core threads. When false (the default), core threads are never
+     * terminated due to lack of incoming tasks.
+     *
+     * @return {@code true} if core threads are allowed to time out,
+     *         else {@code false}
+     *
+     * @since 1.6
+     */
+    public boolean allowsCoreThreadTimeOut() {
+        return allowCoreThreadTimeOut;
+    }
+
+    /**
+     * Sets the policy governing whether core threads may time out and
+     * terminate if no tasks arrive within the keep-alive time, being
+     * replaced if needed when new tasks arrive. When false, core
+     * threads are never terminated due to lack of incoming
+     * tasks. When true, the same keep-alive policy applying to
+     * non-core threads applies also to core threads. To avoid
+     * continual thread replacement, the keep-alive time must be
+     * greater than zero when setting {@code true}. This method
+     * should in general be called before the pool is actively used.
+     *
+     * @param value {@code true} if should time out, else {@code false}
+     * @throws IllegalArgumentException if value is {@code true}
+     *         and the current keep-alive time is not greater than zero
+     *
+     * @since 1.6
+     */
+    public void allowCoreThreadTimeOut(boolean value) {
+        if (value && keepAliveTime <= 0)
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        if (value != allowCoreThreadTimeOut) {
+            allowCoreThreadTimeOut = value;
+            if (value)
+                interruptIdleWorkers();
+        }
+    }
+
+    /**
+     * Sets the maximum allowed number of threads. This overrides any
+     * value set in the constructor. If the new value is smaller than
+     * the current value, excess existing threads will be
+     * terminated when they next become idle.
+     *
+     * @param maximumPoolSize the new maximum
+     * @throws IllegalArgumentException if the new maximum is
+     *         less than or equal to zero, or
+     *         less than the {@linkplain #getCorePoolSize core pool size}
+     * @see #getMaximumPoolSize
+     */
+    public void setMaximumPoolSize(int maximumPoolSize) {
+        if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
+            throw new IllegalArgumentException();
+        this.maximumPoolSize = maximumPoolSize;
+        if (workerCountOf(ctl.get()) > maximumPoolSize)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the maximum allowed number of threads.
+     *
+     * @return the maximum allowed number of threads
+     * @see #setMaximumPoolSize
+     */
+    public int getMaximumPoolSize() {
+        return maximumPoolSize;
+    }
+
+    /**
+     * Sets the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     * This overrides any value set in the constructor.
+     *
+     * @param time the time to wait.  A time value of zero will cause
+     *        excess threads to terminate immediately after executing tasks.
+     * @param unit the time unit of the {@code time} argument
+     * @throws IllegalArgumentException if {@code time} less than zero or
+     *         if {@code time} is zero and {@code allowsCoreThreadTimeOut}
+     * @see #getKeepAliveTime(TimeUnit)
+     */
+    public void setKeepAliveTime(long time, TimeUnit unit) {
+        if (time < 0)
+            throw new IllegalArgumentException();
+        if (time == 0 && allowsCoreThreadTimeOut())
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        long keepAliveTime = unit.toNanos(time);
+        long delta = keepAliveTime - this.keepAliveTime;
+        this.keepAliveTime = keepAliveTime;
+        if (delta < 0)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     *
+     * @param unit the desired time unit of the result
+     * @return the time limit
+     * @see #setKeepAliveTime(long, TimeUnit)
+     */
+    public long getKeepAliveTime(TimeUnit unit) {
+        return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
+    }
+
+    /* User-level queue utilities */
+
+    /**
+     * Returns the task queue used by this executor. Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return workQueue;
+    }
+
+    /**
+     * Removes this task from the executor's internal queue if it is
+     * present, thus causing it not to be run if it has not already
+     * started.
+     *
+     * <p>This method may be useful as one part of a cancellation
+     * scheme.  It may fail to remove tasks that have been converted
+     * into other forms before being placed on the internal queue.
+     * For example, a task entered using {@code submit} might be
+     * converted into a form that maintains {@code Future} status.
+     * However, in such cases, method {@link #purge} may be used to
+     * remove those Futures that have been cancelled.
+     *
+     * @param task the task to remove
+     * @return {@code true} if the task was removed
+     */
+    public boolean remove(Runnable task) {
+        boolean removed = workQueue.remove(task);
+        tryTerminate(); // In case SHUTDOWN and now empty
+        return removed;
+    }
+
+    /**
+     * Tries to remove from the work queue all {@link Future}
+     * tasks that have been cancelled. This method can be useful as a
+     * storage reclamation operation, that has no other impact on
+     * functionality. Cancelled tasks are never executed, but may
+     * accumulate in work queues until worker threads can actively
+     * remove them. Invoking this method instead tries to remove them now.
+     * However, this method may fail to remove tasks in
+     * the presence of interference by other threads.
+     */
+    public void purge() {
+        final BlockingQueue<Runnable> q = workQueue;
+        try {
+            Iterator<Runnable> it = q.iterator();
+            while (it.hasNext()) {
+                Runnable r = it.next();
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    it.remove();
+            }
+        } catch (ConcurrentModificationException fallThrough) {
+            // Take slow path if we encounter interference during traversal.
+            // Make copy for traversal and call remove for cancelled entries.
+            // The slow path is more likely to be O(N*N).
+            for (Object r : q.toArray())
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    q.remove(r);
+        }
+
+        tryTerminate(); // In case SHUTDOWN and now empty
+    }
+
+    /* Statistics */
+
+    /**
+     * Returns the current number of threads in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            // Remove rare and surprising possibility of
+            // isTerminated() && getPoolSize() > 0
+            return runStateAtLeast(ctl.get(), TIDYING) ? 0
+                : workers.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate number of threads that are actively
+     * executing tasks.
+     *
+     * @return the number of threads
+     */
+    public int getActiveCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            int n = 0;
+            for (Worker w : workers)
+                if (w.isLocked())
+                    ++n;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the largest number of threads that have ever
+     * simultaneously been in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getLargestPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            return largestPoolSize;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have ever been
+     * scheduled for execution. Because the states of tasks and
+     * threads may change dynamically during computation, the returned
+     * value is only an approximation.
+     *
+     * @return the number of tasks
+     */
+    public long getTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers) {
+                n += w.completedTasks;
+                if (w.isLocked())
+                    ++n;
+            }
+            return n + workQueue.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have
+     * completed execution. Because the states of tasks and threads
+     * may change dynamically during computation, the returned value
+     * is only an approximation, but one that does not ever decrease
+     * across successive calls.
+     *
+     * @return the number of tasks
+     */
+    public long getCompletedTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers)
+                n += w.completedTasks;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state and estimated worker and
+     * task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        long ncompleted;
+        int nworkers, nactive;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            ncompleted = completedTaskCount;
+            nactive = 0;
+            nworkers = workers.size();
+            for (Worker w : workers) {
+                ncompleted += w.completedTasks;
+                if (w.isLocked())
+                    ++nactive;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+        int c = ctl.get();
+        String runState =
+            isRunning(c) ? "Running" :
+            runStateAtLeast(c, TERMINATED) ? "Terminated" :
+            "Shutting down";
+        return super.toString() +
+            "[" + runState +
+            ", pool size = " + nworkers +
+            ", active threads = " + nactive +
+            ", queued tasks = " + workQueue.size() +
+            ", completed tasks = " + ncompleted +
+            "]";
+    }
+
+    /* Extension hooks */
+
+    /**
+     * Method invoked prior to executing the given Runnable in the
+     * given thread.  This method is invoked by thread {@code t} that
+     * will execute task {@code r}, and may be used to re-initialize
+     * ThreadLocals, or to perform logging.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.beforeExecute} at the end of
+     * this method.
+     *
+     * @param t the thread that will run task {@code r}
+     * @param r the task that will be executed
+     */
+    protected void beforeExecute(Thread t, Runnable r) { }
+
+    /**
+     * Method invoked upon completion of execution of the given Runnable.
+     * This method is invoked by the thread that executed the task. If
+     * non-null, the Throwable is the uncaught {@code RuntimeException}
+     * or {@code Error} that caused execution to terminate abruptly.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.afterExecute} at the
+     * beginning of this method.
+     *
+     * <p><b>Note:</b> When actions are enclosed in tasks (such as
+     * {@link FutureTask}) either explicitly or via methods such as
+     * {@code submit}, these task objects catch and maintain
+     * computational exceptions, and so they do not cause abrupt
+     * termination, and the internal exceptions are <em>not</em>
+     * passed to this method. If you would like to trap both kinds of
+     * failures in this method, you can further probe for such cases,
+     * as in this sample subclass that prints either the direct cause
+     * or the underlying exception if a task has been aborted:
+     *
+     * <pre> {@code
+     * class ExtendedExecutor extends ThreadPoolExecutor {
+     *   // ...
+     *   protected void afterExecute(Runnable r, Throwable t) {
+     *     super.afterExecute(r, t);
+     *     if (t == null
+     *         && r instanceof Future<?>
+     *         && ((Future<?>)r).isDone()) {
+     *       try {
+     *         Object result = ((Future<?>) r).get();
+     *       } catch (CancellationException ce) {
+     *         t = ce;
+     *       } catch (ExecutionException ee) {
+     *         t = ee.getCause();
+     *       } catch (InterruptedException ie) {
+     *         // ignore/reset
+     *         Thread.currentThread().interrupt();
+     *       }
+     *     }
+     *     if (t != null)
+     *       System.out.println(t);
+     *   }
+     * }}</pre>
+     *
+     * @param r the runnable that has completed
+     * @param t the exception that caused termination, or null if
+     * execution completed normally
+     */
+    protected void afterExecute(Runnable r, Throwable t) { }
+
+    /**
+     * Method invoked when the Executor has terminated.  Default
+     * implementation does nothing. Note: To properly nest multiple
+     * overridings, subclasses should generally invoke
+     * {@code super.terminated} within this method.
+     */
+    protected void terminated() { }
+
+    /* Predefined RejectedExecutionHandlers */
+
+    /**
+     * A handler for rejected tasks that runs the rejected task
+     * directly in the calling thread of the {@code execute} method,
+     * unless the executor has been shut down, in which case the task
+     * is discarded.
+     */
+    public static class CallerRunsPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code CallerRunsPolicy}.
+         */
+        public CallerRunsPolicy() { }
+
+        /**
+         * Executes task r in the caller's thread, unless the executor
+         * has been shut down, in which case the task is discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                r.run();
+            }
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that throws a
+     * {@link RejectedExecutionException}.
+     *
+     * This is the default handler for {@link ThreadPoolExecutor} and
+     * {@link ScheduledThreadPoolExecutor}.
+     */
+    public static class AbortPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates an {@code AbortPolicy}.
+         */
+        public AbortPolicy() { }
+
+        /**
+         * Always throws RejectedExecutionException.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         * @throws RejectedExecutionException always
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            throw new RejectedExecutionException("Task " + r.toString() +
+                                                 " rejected from " +
+                                                 e.toString());
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that silently discards the
+     * rejected task.
+     */
+    public static class DiscardPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardPolicy}.
+         */
+        public DiscardPolicy() { }
+
+        /**
+         * Does nothing, which has the effect of discarding task r.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that discards the oldest unhandled
+     * request and then retries {@code execute}, unless the executor
+     * is shut down, in which case the task is discarded. This policy is
+     * rarely useful in cases where other threads may be waiting for
+     * tasks to terminate, or failures must be recorded. Instead consider
+     * using a handler of the form:
+     * <pre> {@code
+     * new RejectedExecutionHandler() {
+     *   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+     *     Runnable dropped = e.getQueue().poll();
+     *     if (dropped instanceof Future<?>) {
+     *       ((Future<?>)dropped).cancel(false);
+     *       // also consider logging the failure
+     *     }
+     *     e.execute(r);  // retry
+     * }}}</pre>
+     */
+    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardOldestPolicy} for the given executor.
+         */
+        public DiscardOldestPolicy() { }
+
+        /**
+         * Obtains and ignores the next task that the executor
+         * would otherwise execute, if one is immediately available,
+         * and then retries execution of task r, unless the executor
+         * is shut down, in which case task r is instead discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                e.getQueue().poll();
+                e.execute(r);
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/TimeUnit.java b/android-35/java/util/concurrent/TimeUnit.java
new file mode 100644
index 0000000..f02aa9f
--- /dev/null
+++ b/android-35/java/util/concurrent/TimeUnit.java
@@ -0,0 +1,494 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Objects;
+
+/**
+ * A {@code TimeUnit} represents time durations at a given unit of
+ * granularity and provides utility methods to convert across units,
+ * and to perform timing and delay operations in these units.  A
+ * {@code TimeUnit} does not maintain time information, but only
+ * helps organize and use time representations that may be maintained
+ * separately across various contexts.  A nanosecond is defined as one
+ * thousandth of a microsecond, a microsecond as one thousandth of a
+ * millisecond, a millisecond as one thousandth of a second, a minute
+ * as sixty seconds, an hour as sixty minutes, and a day as twenty four
+ * hours.
+ *
+ * <p>A {@code TimeUnit} is mainly used to inform time-based methods
+ * how a given timing parameter should be interpreted. For example,
+ * the following code will timeout in 50 milliseconds if the {@link
+ * java.util.concurrent.locks.Lock lock} is not available:
+ *
+ * <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
+ *
+ * while this code will timeout in 50 seconds:
+ * <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
+ * same granularity as the given {@code TimeUnit}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public enum TimeUnit {
+    /**
+     * Time unit representing one thousandth of a microsecond.
+     */
+    NANOSECONDS(TimeUnit.NANO_SCALE),
+    /**
+     * Time unit representing one thousandth of a millisecond.
+     */
+    MICROSECONDS(TimeUnit.MICRO_SCALE),
+    /**
+     * Time unit representing one thousandth of a second.
+     */
+    MILLISECONDS(TimeUnit.MILLI_SCALE),
+    /**
+     * Time unit representing one second.
+     */
+    SECONDS(TimeUnit.SECOND_SCALE),
+    /**
+     * Time unit representing sixty seconds.
+     * @since 1.6
+     */
+    MINUTES(TimeUnit.MINUTE_SCALE),
+    /**
+     * Time unit representing sixty minutes.
+     * @since 1.6
+     */
+    HOURS(TimeUnit.HOUR_SCALE),
+    /**
+     * Time unit representing twenty four hours.
+     * @since 1.6
+     */
+    DAYS(TimeUnit.DAY_SCALE);
+
+    // Scales as constants
+    private static final long NANO_SCALE   = 1L;
+    private static final long MICRO_SCALE  = 1000L * NANO_SCALE;
+    private static final long MILLI_SCALE  = 1000L * MICRO_SCALE;
+    private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
+    private static final long MINUTE_SCALE = 60L * SECOND_SCALE;
+    private static final long HOUR_SCALE   = 60L * MINUTE_SCALE;
+    private static final long DAY_SCALE    = 24L * HOUR_SCALE;
+
+    /*
+     * Instances cache conversion ratios and saturation cutoffs for
+     * the units up through SECONDS. Other cases compute them, in
+     * method cvt.
+     */
+
+    private final long scale;
+    private final long maxNanos;
+    private final long maxMicros;
+    private final long maxMillis;
+    private final long maxSecs;
+    private final long microRatio;
+    private final int milliRatio;   // fits in 32 bits
+    private final int secRatio;     // fits in 32 bits
+
+    private TimeUnit(long s) {
+        this.scale = s;
+        this.maxNanos = Long.MAX_VALUE / s;
+        long ur = (s >= MICRO_SCALE) ? (s / MICRO_SCALE) : (MICRO_SCALE / s);
+        this.microRatio = ur;
+        this.maxMicros = Long.MAX_VALUE / ur;
+        long mr = (s >= MILLI_SCALE) ? (s / MILLI_SCALE) : (MILLI_SCALE / s);
+        this.milliRatio = (int)mr;
+        this.maxMillis = Long.MAX_VALUE / mr;
+        long sr = (s >= SECOND_SCALE) ? (s / SECOND_SCALE) : (SECOND_SCALE / s);
+        this.secRatio = (int)sr;
+        this.maxSecs = Long.MAX_VALUE / sr;
+    }
+
+    /**
+     * General conversion utility.
+     *
+     * @param d duration
+     * @param dst result unit scale
+     * @param src source unit scale
+     */
+    private static long cvt(long d, long dst, long src) {
+        long r, m;
+        if (src == dst)
+            return d;
+        else if (src < dst)
+            return d / (dst / src);
+        else if (d > (m = Long.MAX_VALUE / (r = src / dst)))
+            return Long.MAX_VALUE;
+        else if (d < -m)
+            return Long.MIN_VALUE;
+        else
+            return d * r;
+    }
+
+    /**
+     * Converts the given time duration in the given unit to this unit.
+     * Conversions from finer to coarser granularities truncate, so
+     * lose precision. For example, converting {@code 999} milliseconds
+     * to seconds results in {@code 0}. Conversions from coarser to
+     * finer granularities with arguments that would numerically
+     * overflow saturate to {@code Long.MIN_VALUE} if negative or
+     * {@code Long.MAX_VALUE} if positive.
+     *
+     * <p>For example, to convert 10 minutes to milliseconds, use:
+     * {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)}
+     *
+     * @param sourceDuration the time duration in the given {@code sourceUnit}
+     * @param sourceUnit the unit of the {@code sourceDuration} argument
+     * @return the converted duration in this unit,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long convert(long sourceDuration, TimeUnit sourceUnit) {
+        switch (this) {
+        case NANOSECONDS:  return sourceUnit.toNanos(sourceDuration);
+        case MICROSECONDS: return sourceUnit.toMicros(sourceDuration);
+        case MILLISECONDS: return sourceUnit.toMillis(sourceDuration);
+        case SECONDS:      return sourceUnit.toSeconds(sourceDuration);
+        default: return cvt(sourceDuration, scale, sourceUnit.scale);
+        }
+    }
+
+    /**
+     * Converts the given time duration to this unit.
+     *
+     * <p>For any TimeUnit {@code unit},
+     * {@code unit.convert(Duration.ofNanos(n))}
+     * is equivalent to
+     * {@code unit.convert(n, NANOSECONDS)}, and
+     * {@code unit.convert(Duration.of(n, unit.toChronoUnit()))}
+     * is equivalent to {@code n} (in the absence of overflow).
+     *
+     * @apiNote
+     * This method differs from {@link Duration#toNanos()} in that it
+     * does not throw {@link ArithmeticException} on numeric overflow.
+     *
+     * @param duration the time duration
+     * @return the converted duration in this unit,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @throws NullPointerException if {@code duration} is null
+     * @see Duration#of(long,TemporalUnit)
+     * @since 11
+     */
+    public long convert(Duration duration) {
+        long secs = duration.getSeconds();
+        int nano = duration.getNano();
+        if (secs < 0 && nano > 0) {
+            // use representation compatible with integer division
+            secs++;
+            nano -= (int) SECOND_SCALE;
+        }
+        final long s, nanoVal;
+        // Optimize for the common case - NANOSECONDS without overflow
+        if (this == NANOSECONDS)
+            nanoVal = nano;
+        else if ((s = scale) < SECOND_SCALE)
+            nanoVal = nano / s;
+        else if (this == SECONDS)
+            return secs;
+        else
+            return secs / secRatio;
+        long val = secs * secRatio + nanoVal;
+        return ((secs < maxSecs && secs > -maxSecs) ||
+                (secs == maxSecs && val > 0) ||
+                (secs == -maxSecs && val < 0))
+            ? val
+            : (secs > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toNanos(long duration) {
+        long s, m;
+        if ((s = scale) == NANO_SCALE)
+            return duration;
+        else if (duration > (m = maxNanos))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * s;
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMicros(long duration) {
+        long s, m;
+        if ((s = scale) <= MICRO_SCALE)
+            return (s == MICRO_SCALE) ? duration : duration / microRatio;
+        else if (duration > (m = maxMicros))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * microRatio;
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMillis(long duration) {
+        long s, m;
+        if ((s = scale) <= MILLI_SCALE)
+            return (s == MILLI_SCALE) ? duration : duration / milliRatio;
+        else if (duration > (m = maxMillis))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * milliRatio;
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toSeconds(long duration) {
+        long s, m;
+        if ((s = scale) <= SECOND_SCALE)
+            return (s == SECOND_SCALE) ? duration : duration / secRatio;
+        else if (duration > (m = maxSecs))
+            return Long.MAX_VALUE;
+        else if (duration < -m)
+            return Long.MIN_VALUE;
+        else
+            return duration * secRatio;
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toMinutes(long duration) {
+        return cvt(duration, MINUTE_SCALE, scale);
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively overflow,
+     * or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toHours(long duration) {
+        return cvt(duration, HOUR_SCALE, scale);
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) DAYS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration
+     * @since 1.6
+     */
+    public long toDays(long duration) {
+        return cvt(duration, DAY_SCALE, scale);
+    }
+
+    /**
+     * Utility to compute the excess-nanosecond argument to wait,
+     * sleep, join.
+     * @param d the duration
+     * @param m the number of milliseconds
+     * @return the number of nanoseconds
+     */
+    private int excessNanos(long d, long m) {
+        long s;
+        if ((s = scale) == NANO_SCALE)
+            return (int)(d - (m * MILLI_SCALE));
+        else if (s == MICRO_SCALE)
+            return (int)((d * 1000L) - (m * MILLI_SCALE));
+        else
+            return 0;
+    }
+
+    /**
+     * Performs a timed {@link Object#wait(long, int) Object.wait}
+     * using this time unit.
+     * This is a convenience method that converts timeout arguments
+     * into the form required by the {@code Object.wait} method.
+     *
+     * <p>For example, you could implement a blocking {@code poll} method
+     * (see {@link BlockingQueue#poll(long, TimeUnit) BlockingQueue.poll})
+     * using:
+     *
+     * <pre> {@code
+     * public E poll(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
+     *   synchronized (lock) {
+     *     while (isEmpty()) {
+     *       unit.timedWait(lock, timeout);
+     *       ...
+     *     }
+     *   }
+     * }}</pre>
+     *
+     * @param obj the object to wait on
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedWait(Object obj, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            obj.wait(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a timed {@link Thread#join(long, int) Thread.join}
+     * using this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.join} method.
+     *
+     * @param thread the thread to wait for
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedJoin(Thread thread, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            thread.join(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a {@link Thread#sleep(long, int) Thread.sleep} using
+     * this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.sleep} method.
+     *
+     * @param timeout the minimum time to sleep. If less than
+     * or equal to zero, do not sleep at all.
+     * @throws InterruptedException if interrupted while sleeping
+     */
+    public void sleep(long timeout) throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            Thread.sleep(ms, ns);
+        }
+    }
+
+    /**
+     * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
+     *
+     * @return the converted equivalent ChronoUnit
+     * @since 9
+     */
+    public ChronoUnit toChronoUnit() {
+        switch (this) {
+        case NANOSECONDS:  return ChronoUnit.NANOS;
+        case MICROSECONDS: return ChronoUnit.MICROS;
+        case MILLISECONDS: return ChronoUnit.MILLIS;
+        case SECONDS:      return ChronoUnit.SECONDS;
+        case MINUTES:      return ChronoUnit.MINUTES;
+        case HOURS:        return ChronoUnit.HOURS;
+        case DAYS:         return ChronoUnit.DAYS;
+        default: throw new AssertionError();
+        }
+    }
+
+    /**
+     * Converts a {@code ChronoUnit} to the equivalent {@code TimeUnit}.
+     *
+     * @param chronoUnit the ChronoUnit to convert
+     * @return the converted equivalent TimeUnit
+     * @throws IllegalArgumentException if {@code chronoUnit} has no
+     *         equivalent TimeUnit
+     * @throws NullPointerException if {@code chronoUnit} is null
+     * @since 9
+     */
+    public static TimeUnit of(ChronoUnit chronoUnit) {
+        switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
+        case NANOS:   return TimeUnit.NANOSECONDS;
+        case MICROS:  return TimeUnit.MICROSECONDS;
+        case MILLIS:  return TimeUnit.MILLISECONDS;
+        case SECONDS: return TimeUnit.SECONDS;
+        case MINUTES: return TimeUnit.MINUTES;
+        case HOURS:   return TimeUnit.HOURS;
+        case DAYS:    return TimeUnit.DAYS;
+        default:
+            throw new IllegalArgumentException(
+                "No TimeUnit equivalent for " + chronoUnit);
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/TimeoutException.java b/android-35/java/util/concurrent/TimeoutException.java
new file mode 100644
index 0000000..b54c52b
--- /dev/null
+++ b/android-35/java/util/concurrent/TimeoutException.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a blocking operation times out.  Blocking
+ * operations for which a timeout is specified need a means to
+ * indicate that the timeout has occurred. For many such operations it
+ * is possible to return a value that indicates timeout; when that is
+ * not possible or desirable then {@code TimeoutException} should be
+ * declared and thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class TimeoutException extends Exception {
+    private static final long serialVersionUID = 1900926677490660714L;
+
+    /**
+     * Constructs a {@code TimeoutException} with no specified detail
+     * message.
+     */
+    public TimeoutException() {}
+
+    /**
+     * Constructs a {@code TimeoutException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public TimeoutException(String message) {
+        super(message);
+    }
+}
diff --git a/android-35/java/util/concurrent/TransferQueue.java b/android-35/java/util/concurrent/TransferQueue.java
new file mode 100644
index 0000000..72a4108
--- /dev/null
+++ b/android-35/java/util/concurrent/TransferQueue.java
@@ -0,0 +1,161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * 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.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+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/android-35/java/util/concurrent/atomic/AtomicBoolean.java b/android-35/java/util/concurrent/atomic/AtomicBoolean.java
new file mode 100644
index 0000000..1555c22
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicBoolean.java
@@ -0,0 +1,360 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/**
+ * A {@code boolean} value that may be updated atomically. See the
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicBoolean} is used in
+ * applications such as atomically updated flags, and cannot be used
+ * as a replacement for a {@link java.lang.Boolean}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicBoolean implements java.io.Serializable {
+    private static final long serialVersionUID = 4654671469794556979L;
+    private static final VarHandle VALUE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private volatile int value;
+
+    /**
+     * Creates a new {@code AtomicBoolean} with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicBoolean(boolean initialValue) {
+        if (initialValue)
+            value = 1;
+    }
+
+    /**
+     * Creates a new {@code AtomicBoolean} with initial value {@code false}.
+     */
+    public AtomicBoolean() {
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @return the current value
+     */
+    public final boolean get() {
+        return value != 0;
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
+        return VALUE.compareAndSet(this,
+                                   (expectedValue ? 1 : 0),
+                                   (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public boolean weakCompareAndSet(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetPlain(this,
+                                            (expectedValue ? 1 : 0),
+                                            (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public boolean weakCompareAndSetPlain(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetPlain(this,
+                                            (expectedValue ? 1 : 0),
+                                            (newValue ? 1 : 0));
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param newValue the new value
+     */
+    public final void set(boolean newValue) {
+        value = newValue ? 1 : 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(boolean newValue) {
+        VALUE.setRelease(this, (newValue ? 1 : 0));
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final boolean getAndSet(boolean newValue) {
+        return (int)VALUE.getAndSet(this, (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Boolean.toString(get());
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getPlain() {
+        return (int)VALUE.get(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(boolean newValue) {
+        VALUE.set(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getOpaque() {
+        return (int)VALUE.getOpaque(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(boolean newValue) {
+        VALUE.setOpaque(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final boolean getAcquire() {
+        return (int)VALUE.getAcquire(this) != 0;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(boolean newValue) {
+        VALUE.setRelease(this, newValue ? 1 : 0);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchange(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchange(this,
+                                             (expectedValue ? 1 : 0),
+                                             (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchangeAcquire(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchangeAcquire(this,
+                                                    (expectedValue ? 1 : 0),
+                                                    (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final boolean compareAndExchangeRelease(boolean expectedValue, boolean newValue) {
+        return (int)VALUE.compareAndExchangeRelease(this,
+                                                    (expectedValue ? 1 : 0),
+                                                    (newValue ? 1 : 0)) != 0;
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSet(this,
+                                       (expectedValue ? 1 : 0),
+                                       (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetAcquire(this,
+                                              (expectedValue ? 1 : 0),
+                                              (newValue ? 1 : 0));
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if the current
+     * value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(boolean expectedValue, boolean newValue) {
+        return VALUE.weakCompareAndSetRelease(this,
+                                              (expectedValue ? 1 : 0),
+                                              (newValue ? 1 : 0));
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicInteger.java b/android-35/java/util/concurrent/atomic/AtomicInteger.java
new file mode 100644
index 0000000..b77e08e
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicInteger.java
@@ -0,0 +1,610 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} value that may be updated atomically.  See the
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicInteger} is used in
+ * applications such as atomically incremented counters, and cannot be
+ * used as a replacement for an {@link java.lang.Integer}. However,
+ * this class does extend {@code Number} to allow uniform access by
+ * tools and utilities that deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicInteger extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 6214790243416807050L;
+
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
+    // BEGIN Android-changed: Using VarHandle instead of Unsafe
+    // private static final Unsafe U = Unsafe.getUnsafe();
+    // private static final long VALUE
+    //     = U.objectFieldOffset(AtomicInteger.class, "value");
+    private static final VarHandle VALUE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicInteger.class, "value", int.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+    // END Android-changed: Using VarHandle instead of Unsafe
+
+    private volatile int value;
+
+    /**
+     * Creates a new AtomicInteger with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicInteger(int initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicInteger with initial value {@code 0}.
+     */
+    public AtomicInteger() {
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @return the current value
+     */
+    public final int get() {
+        return value;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param newValue the new value
+     */
+    public final void set(int newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putIntRelease(this, VALUE, newValue);
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndSetInt(this, VALUE, newValue);
+        return (int)VALUE.getAndSet(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
+        return VALUE.compareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetIntPlain(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetIntPlain(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(1)}.
+     *
+     * @return the previous value
+     */
+    public final int getAndIncrement() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, 1);
+        return (int)VALUE.getAndAdd(this, 1);
+    }
+
+    /**
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(-1)}.
+     *
+     * @return the previous value
+     */
+    public final int getAndDecrement() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, -1);
+        return (int)VALUE.getAndAdd(this, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int delta) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, delta);
+        return (int)VALUE.getAndAdd(this, delta);
+    }
+
+    /**
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(1)}.
+     *
+     * @return the updated value
+     */
+    public final int incrementAndGet() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, 1) + 1;
+        return (int)VALUE.getAndAdd(this, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(-1)}.
+     *
+     * @return the updated value
+     */
+    public final int decrementAndGet() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, -1) - 1;
+        return (int)VALUE.getAndAdd(this, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int delta) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddInt(this, VALUE, delta) + delta;
+        return (int)VALUE.getAndAdd(this, delta) + delta;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(IntUnaryOperator updateFunction) {
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(IntUnaryOperator updateFunction) {
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev = get(), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Integer.toString(get());
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicInteger} as an
+     * {@code int},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * Equivalent to {@link #get()}.
+     */
+    public int intValue() {
+        return get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code long} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.2 Widening Primitive Conversion
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code float} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.2 Widening Primitive Conversion
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicInteger} as a
+     * {@code double} after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.2 Widening Primitive Conversion
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getPlain() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getInt(this, VALUE);
+        return (int)VALUE.get(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putInt(this, VALUE, newValue);
+        VALUE.set(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getOpaque() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getIntOpaque(this, VALUE);
+        return (int)VALUE.getOpaque(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putIntOpaque(this, VALUE, newValue);
+        VALUE.setOpaque(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final int getAcquire() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getIntAcquire(this, VALUE);
+        return (int)VALUE.getAcquire(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putIntRelease(this, VALUE, newValue);
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchange(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeInt(this, VALUE, expectedValue, newValue);
+        return (int)VALUE.compareAndExchange(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeIntAcquire(this, VALUE, expectedValue, newValue);
+        return (int)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeRelease(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeIntRelease(this, VALUE, expectedValue, newValue);
+        return (int)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        //return U.weakCompareAndSetInt(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetIntAcquire(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue} if
+     * the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetIntRelease(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicIntegerArray.java b/android-35/java/util/concurrent/atomic/AtomicIntegerArray.java
new file mode 100644
index 0000000..f59327d
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -0,0 +1,566 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} array in which elements may be updated atomically.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicIntegerArray implements java.io.Serializable {
+    private static final long serialVersionUID = 2862133569453604235L;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(int[].class);
+    private final int[] array;
+
+    /**
+     * Creates a new AtomicIntegerArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicIntegerArray(int length) {
+        array = new int[length];
+    }
+
+    /**
+     * Creates a new AtomicIntegerArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicIntegerArray(int[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final int get(int i) {
+        return (int)AA.getVolatile(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, int newValue) {
+        AA.setVolatile(array, i, newValue);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, int newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int i, int newValue) {
+        return (int)AA.getAndSet(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, int expectedValue, int newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, 1)}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndIncrement(int i) {
+        return (int)AA.getAndAdd(array, i, 1);
+    }
+
+    /**
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, -1)}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndDecrement(int i) {
+        return (int)AA.getAndAdd(array, i, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int i, int delta) {
+        return (int)AA.getAndAdd(array, i, delta);
+    }
+
+    /**
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, 1)}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int incrementAndGet(int i) {
+        return (int)AA.getAndAdd(array, i, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, -1)}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int decrementAndGet(int i) {
+        return (int)AA.getAndAdd(array, i, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int i, int delta) {
+        return (int)AA.getAndAdd(array, i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * previous value. The function should be side-effect-free, since
+     * it may be re-applied when attempted updates fail due to
+     * contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * updated value. The function should be side-effect-free, since it
+     * may be re-applied when attempted updates fail due to contention
+     * among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsInt(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev = get(i), next = 0;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsInt(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(get(i));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getPlain(int i) {
+        return (int)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, int newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getOpaque(int i) {
+        return (int)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, int newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final int getAcquire(int i) {
+        return (int)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, int newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchange(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeAcquire(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final int compareAndExchangeRelease(int i, int expectedValue, int newValue) {
+        return (int)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, int expectedValue, int newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+    }
+
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/android-35/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
new file mode 100644
index 0000000..d84b957
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -0,0 +1,562 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile int} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicIntegerFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile integer type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                              String fieldName) {
+        return new AtomicIntegerFieldUpdaterImpl<U>
+            (tclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicIntegerFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean compareAndSet(T obj, int expect, int update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p>This operation may fail spuriously and does not provide
+     * ordering guarantees, so is only rarely an appropriate
+     * alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean weakCompareAndSet(T obj, int expect, int update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, int newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, int newValue);
+
+    /**
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract int get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public int getAndSet(T obj, int newValue) {
+        int prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndIncrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndDecrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public int getAndAdd(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int incrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int decrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public int addAndGet(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the previous value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the updated value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Standard hotspot implementation using intrinsics.
+     */
+    private static final class AtomicIntegerFieldUpdaterImpl<T>
+        extends AtomicIntegerFieldUpdater<T> {
+        private static final Unsafe U = Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        @SuppressWarnings("removal")
+        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
+                                      final String fieldName,
+                                      final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // BEGIN Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                // END Android-changed: Skip privilege escalation which is a noop on Android.
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // BEGIN Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                // END Android-removed: Skip checkPackageAccess which is a noop on Android.
+            // BEGIN Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            // END Android-removed: Skip privilege escalation which is a noop on Android.
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != int.class)
+                throw new IllegalArgumentException("Must be integer type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // BEGIN Android-removed: isAncestor()'s only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+        // END Android-removed: isAncestor()'s only usage was removed above.
+
+        /**
+         * Returns true if the two classes have the same class loader and
+         * package qualifier
+         */
+        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+            return class1.getClassLoader() == class2.getClassLoader()
+                   && class1.getPackageName() == class2.getPackageName();
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSetInt(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSetInt(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, int newValue) {
+            accessCheck(obj);
+            U.putIntVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, int newValue) {
+            accessCheck(obj);
+            U.putIntRelease(obj, offset, newValue);
+        }
+
+        public final int get(T obj) {
+            accessCheck(obj);
+            return U.getIntVolatile(obj, offset);
+        }
+
+        public final int getAndSet(T obj, int newValue) {
+            accessCheck(obj);
+            return U.getAndSetInt(obj, offset, newValue);
+        }
+
+        public final int getAndAdd(T obj, int delta) {
+            accessCheck(obj);
+            return U.getAndAddInt(obj, offset, delta);
+        }
+
+        public final int getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final int getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final int incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final int decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final int addAndGet(T obj, int delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+
+    }
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicLong.java b/android-35/java/util/concurrent/atomic/AtomicLong.java
new file mode 100644
index 0000000..323a513
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicLong.java
@@ -0,0 +1,625 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} value that may be updated atomically.  See the
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicLong} is used in applications
+ * such as atomically incremented sequence numbers, and cannot be used
+ * as a replacement for a {@link java.lang.Long}. However, this class
+ * does extend {@code Number} to allow uniform access by tools and
+ * utilities that deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLong extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 1927816293512124184L;
+
+    /**
+     * Records whether the underlying JVM supports lockless
+     * compareAndSet for longs. While the intrinsic compareAndSetLong
+     * method works in either case, some constructions should be
+     * handled at Java level to avoid locking user-visible locks.
+     */
+    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
+
+    /**
+     * Returns whether underlying JVM supports lockless CompareAndSet
+     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
+     */
+    private static native boolean VMSupportsCS8();
+
+    /*
+     * This class intended to be implemented using VarHandles, but there
+     * are unresolved cyclic startup dependencies.
+     */
+    // BEGIN Android-changed: Using VarHandle instead of Unsafe
+    // private static final Unsafe U = Unsafe.getUnsafe();
+    // private static final long VALUE
+    //     = U.objectFieldOffset(AtomicLong.class, "value");
+    private static final VarHandle VALUE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicLong.class, "value", long.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+    // END Android-changed: Using VarHandle instead of Unsafe
+
+    private volatile long value;
+
+    /**
+     * Creates a new AtomicLong with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicLong(long initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicLong with initial value {@code 0}.
+     */
+    public AtomicLong() {
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @return the current value
+     */
+    public final long get() {
+        return value;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param newValue the new value
+     */
+    public final void set(long newValue) {
+        // See JDK-8180620: Clarify VarHandle mixed-access subtleties
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putLongVolatile(this, VALUE, newValue);
+        VALUE.setVolatile(this, newValue);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putLongRelease(this, VALUE, newValue);
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndSetLong(this, VALUE, newValue);
+        return (long)VALUE.getAndSet(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndSetLong(this, VALUE, expectedValue, newValue);
+        return VALUE.compareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetLongPlain(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetLongPlain(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(1)}.
+     *
+     * @return the previous value
+     */
+    public final long getAndIncrement() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, 1L);
+        return (long)VALUE.getAndAdd(this, 1L);
+    }
+
+    /**
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(-1)}.
+     *
+     * @return the previous value
+     */
+    public final long getAndDecrement() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, -1L);
+        return (long)VALUE.getAndAdd(this, -1L);
+    }
+
+    /**
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(long delta) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, delta);
+        return (long)VALUE.getAndAdd(this, delta);
+    }
+
+    /**
+     * Atomically increments the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(1)}.
+     *
+     * @return the updated value
+     */
+    public final long incrementAndGet() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, 1L) + 1L;
+        return (long)VALUE.getAndAdd(this, 1L) + 1L;
+    }
+
+    /**
+     * Atomically decrements the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(-1)}.
+     *
+     * @return the updated value
+     */
+    public final long decrementAndGet() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, -1L) - 1L;
+        return (long)VALUE.getAndAdd(this, -1L) - 1L;
+    }
+
+    /**
+     * Atomically adds the given value to the current value,
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final long addAndGet(long delta) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getAndAddLong(this, VALUE, delta) + delta;
+        return (long)VALUE.getAndAdd(this, delta) + delta;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(LongUnaryOperator updateFunction) {
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(LongUnaryOperator updateFunction) {
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev = get(), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicLong} as an {@code int}
+     * after a narrowing primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.3 Narrowing Primitive Conversion
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicLong} as a {@code long},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * Equivalent to {@link #get()}.
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicLong} as a {@code float}
+     * after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.2 Widening Primitive Conversion
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the current value of this {@code AtomicLong} as a {@code double}
+     * after a widening primitive conversion,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     * @jls 5.1.2 Widening Primitive Conversion
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as if the
+     * variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getPlain() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getLong(this, VALUE);
+        return (long)VALUE.get(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putLong(this, VALUE, newValue);
+        VALUE.set(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getOpaque() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getLongOpaque(this, VALUE);
+        return (long)VALUE.getOpaque(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putLongOpaque(this, VALUE, newValue);
+        VALUE.setOpaque(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final long getAcquire() {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.getLongAcquire(this, VALUE);
+        return (long)VALUE.getAcquire(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // U.putLongRelease(this, VALUE, newValue);
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchange(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeLong(this, VALUE, expectedValue, newValue);
+        return (long)VALUE.compareAndExchange(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeLongAcquire(this, VALUE, expectedValue, newValue);
+        return (long)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeRelease(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.compareAndExchangeLongRelease(this, VALUE, expectedValue, newValue);
+        return (long)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetLong(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetLongAcquire(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
+        // Android-changed: Using VarHandle instead of Unsafe
+        // return U.weakCompareAndSetLongRelease(this, VALUE, expectedValue, newValue);
+        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicLongArray.java b/android-35/java/util/concurrent/atomic/AtomicLongArray.java
new file mode 100644
index 0000000..24e42a1
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicLongArray.java
@@ -0,0 +1,565 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} array in which elements may be updated atomically.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLongArray implements java.io.Serializable {
+    private static final long serialVersionUID = -2308431214976778248L;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(long[].class);
+    private final long[] array;
+
+    /**
+     * Creates a new AtomicLongArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicLongArray(int length) {
+        array = new long[length];
+    }
+
+    /**
+     * Creates a new AtomicLongArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicLongArray(long[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final long get(int i) {
+        return (long)AA.getVolatile(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, long newValue) {
+        AA.setVolatile(array, i, newValue);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, long newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(int i, long newValue) {
+        return (long)AA.getAndSet(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, long expectedValue, long newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, 1)}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndIncrement(int i) {
+        return (long)AA.getAndAdd(array, i, 1L);
+    }
+
+    /**
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code getAndAdd(i, -1)}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndDecrement(int i) {
+        return (long)AA.getAndAdd(array, i, -1L);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(int i, long delta) {
+        return (long)AA.getAndAdd(array, i, delta);
+    }
+
+    /**
+     * Atomically increments the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, 1)}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long incrementAndGet(int i) {
+        return (long)AA.getAndAdd(array, i, 1L) + 1L;
+    }
+
+    /**
+     * Atomically decrements the value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * <p>Equivalent to {@code addAndGet(i, -1)}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long decrementAndGet(int i) {
+        return (long)AA.getAndAdd(array, i, -1L) - 1L;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAndAdd}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(int i, long delta) {
+        return (long)AA.getAndAdd(array, i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * previous value. The function should be side-effect-free, since
+     * it may be re-applied when attempted updates fail due to
+     * contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * updated value. The function should be side-effect-free, since it
+     * may be re-applied when attempted updates fail due to contention
+     * among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.applyAsLong(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long prev = get(i), next = 0L;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.applyAsLong(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(get(i));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getPlain(int i) {
+        return (long)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, long newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getOpaque(int i) {
+        return (long)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, long newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final long getAcquire(int i) {
+        return (long)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, long newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchange(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeAcquire(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final long compareAndExchangeRelease(int i, long expectedValue, long newValue) {
+        return (long)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, long expectedValue, long newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/android-35/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
new file mode 100644
index 0000000..08830cd
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -0,0 +1,685 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile long} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicLongFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile long type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                           String fieldName) {
+        Class<?> caller = Reflection.getCallerClass();
+        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
+            return new CASUpdater<U>(tclass, fieldName, caller);
+        else
+            return new LockedUpdater<U>(tclass, fieldName, caller);
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicLongFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean compareAndSet(T obj, long expect, long update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p>This operation may fail spuriously and does not provide
+     * ordering guarantees, so is only rarely an appropriate
+     * alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean weakCompareAndSet(T obj, long expect, long update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, long newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, long newValue);
+
+    /**
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract long get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public long getAndSet(T obj, long newValue) {
+        long prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndIncrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndDecrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public long getAndAdd(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long incrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long decrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the previous value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the updated value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final Unsafe U = Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        @SuppressWarnings("removal")
+        CASUpdater(final Class<T> tclass, final String fieldName,
+                   final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSetLong(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSetLong(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            U.putLongVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            accessCheck(obj);
+            U.putLongRelease(obj, offset, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            return U.getLongVolatile(obj, offset);
+        }
+
+        public final long getAndSet(T obj, long newValue) {
+            accessCheck(obj);
+            return U.getAndSetLong(obj, offset, newValue);
+        }
+
+        public final long getAndAdd(T obj, long delta) {
+            accessCheck(obj);
+            return U.getAndAddLong(obj, offset, delta);
+        }
+
+        public final long getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final long getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final long incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final long decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final long addAndGet(T obj, long delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+    }
+
+    private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final Unsafe U = Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        @SuppressWarnings("removal")
+        LockedUpdater(final Class<T> tclass, final String fieldName,
+                      final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throw accessCheckException(obj);
+        }
+
+        /**
+         * Returns access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final RuntimeException accessCheckException(T obj) {
+            if (cclass == tclass)
+                return new ClassCastException();
+            else
+                return new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            synchronized (this) {
+                long v = U.getLong(obj, offset);
+                if (v != expect)
+                    return false;
+                U.putLong(obj, offset, update);
+                return true;
+            }
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            return compareAndSet(obj, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            synchronized (this) {
+                U.putLong(obj, offset, newValue);
+            }
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            set(obj, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            synchronized (this) {
+                return U.getLong(obj, offset);
+            }
+        }
+    }
+
+    // Android-removed: isAncestor's only usage was removed above.
+    /*
+    /**
+     * Returns true if the second classloader can be found in the first
+     * classloader's delegation chain.
+     * Equivalent to the inaccessible: first.isAncestor(second).
+     *
+    static boolean isAncestor(ClassLoader first, ClassLoader second) {
+        ClassLoader acl = first;
+        do {
+            acl = acl.getParent();
+            if (second == acl) {
+                return true;
+            }
+        } while (acl != null);
+        return false;
+    }
+    */
+
+    /**
+     * Returns true if the two classes have the same class loader and
+     * package qualifier
+     */
+    static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+        return class1.getClassLoader() == class2.getClassLoader()
+               && class1.getPackageName() == class2.getPackageName();
+    }
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicMarkableReference.java b/android-35/java/util/concurrent/atomic/AtomicMarkableReference.java
new file mode 100644
index 0000000..8e1727c
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/**
+ * An {@code AtomicMarkableReference} maintains an object reference
+ * along with a mark bit, that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains markable
+ * references by creating internal objects representing "boxed"
+ * [reference, boolean] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicMarkableReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final boolean mark;
+        private Pair(T reference, boolean mark) {
+            this.reference = reference;
+            this.mark = mark;
+        }
+        static <T> Pair<T> of(T reference, boolean mark) {
+            return new Pair<T>(reference, mark);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicMarkableReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialMark the initial mark
+     */
+    public AtomicMarkableReference(V initialRef, boolean initialMark) {
+        pair = Pair.of(initialRef, initialMark);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the mark.
+     *
+     * @return the current value of the mark
+     */
+    public boolean isMarked() {
+        return pair.mark;
+    }
+
+    /**
+     * Returns the current values of both the reference and the mark.
+     * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
+     *
+     * @param markHolder an array of size of at least one. On return,
+     * {@code markHolder[0]} will hold the value of the mark.
+     * @return the current value of the reference
+     */
+    public V get(boolean[] markHolder) {
+        Pair<V> pair = this.pair;
+        markHolder[0] = pair.mark;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark to the
+     * given update values if the current reference is {@code ==} to
+     * the expected reference and the current mark is equal to the
+     * expected mark. This operation may fail spuriously and does not
+     * provide ordering guarantees, so is only rarely an
+     * appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V       expectedReference,
+                                     V       newReference,
+                                     boolean expectedMark,
+                                     boolean newMark) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedMark, newMark);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current mark is equal to the expected mark.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V       expectedReference,
+                                 V       newReference,
+                                 boolean expectedMark,
+                                 boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedMark == current.mark &&
+            ((newReference == current.reference &&
+              newMark == current.mark) ||
+             casPair(current, Pair.of(newReference, newMark)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and mark.
+     *
+     * @param newReference the new value for the reference
+     * @param newMark the new value for the mark
+     */
+    public void set(V newReference, boolean newMark) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newMark != current.mark)
+            this.pair = Pair.of(newReference, newMark);
+    }
+
+    /**
+     * Atomically sets the value of the mark to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean attemptMark(V expectedReference, boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newMark == current.mark ||
+             casPair(current, Pair.of(expectedReference, newMark)));
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
+                                   Pair.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return PAIR.compareAndSet(this, cmp, val);
+    }
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicReference.java b/android-35/java/util/concurrent/atomic/AtomicReference.java
new file mode 100644
index 0000000..03dd039
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicReference.java
@@ -0,0 +1,441 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An object reference that may be updated atomically.  See the {@link
+ * VarHandle} specification for descriptions of the properties of
+ * atomic accesses.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicReference<V> implements java.io.Serializable {
+    private static final long serialVersionUID = -1848883965231344442L;
+    private static final VarHandle VALUE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    @SuppressWarnings("serial") // Conditionally serializable
+    private volatile V value;
+
+    /**
+     * Creates a new AtomicReference with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicReference(V initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicReference with null initial value.
+     */
+    public AtomicReference() {
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @return the current value
+     */
+    public final V get() {
+        return value;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param newValue the new value
+     */
+    public final void set(V newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(V newValue) {
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(V expectedValue, V newValue) {
+        return VALUE.compareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetPlain(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final V getAndSet(V newValue) {
+        return (V)VALUE.getAndSet(this, newValue);
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(UnaryOperator<V> updateFunction) {
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(UnaryOperator<V> updateFunction) {
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return prev;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value as its first argument, and the
+     * given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev = get(), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(prev, next))
+                return next;
+            haveNext = (prev == (prev = get()));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return String.valueOf(get());
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getPlain() {
+        return (V)VALUE.get(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue}, with memory semantics
+     * of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(V newValue) {
+        VALUE.set(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getOpaque() {
+        return (V)VALUE.getOpaque(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(V newValue) {
+        VALUE.setOpaque(this, newValue);
+    }
+
+    /**
+     * Returns the current value,
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @return the value
+     * @since 9
+     */
+    public final V getAcquire() {
+        return (V)VALUE.getAcquire(this);
+    }
+
+    /**
+     * Sets the value to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(V newValue) {
+        VALUE.setRelease(this, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchange(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchange(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchangeAcquire(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the value to {@code newValue} if the current value,
+     * referred to as the <em>witness value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final V compareAndExchangeRelease(V expectedValue, V newValue) {
+        return (V)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the value to {@code newValue}
+     * if the current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(V expectedValue, V newValue) {
+        return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicReferenceArray.java b/android-35/java/util/concurrent/atomic/AtomicReferenceArray.java
new file mode 100644
index 0000000..b1ad0a9
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -0,0 +1,529 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An array of object references in which elements may be updated
+ * atomically.  See the {@link VarHandle} specification for
+ * descriptions of the properties of atomic accesses.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> The base class of elements held in this array
+ */
+public class AtomicReferenceArray<E> implements java.io.Serializable {
+    private static final long serialVersionUID = -6209656149925076980L;
+    private static final VarHandle AA
+        = MethodHandles.arrayElementVarHandle(Object[].class);
+    @SuppressWarnings("serial") // Conditionally serializable
+    private final Object[] array; // must have exact type Object[]
+
+    /**
+     * Creates a new AtomicReferenceArray of the given length, with all
+     * elements initially null.
+     *
+     * @param length the length of the array
+     */
+    public AtomicReferenceArray(int length) {
+        array = new Object[length];
+    }
+
+    /**
+     * Creates a new AtomicReferenceArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicReferenceArray(E[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = Arrays.copyOf(array, array.length, Object[].class);
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getVolatile}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    @SuppressWarnings("unchecked")
+    public final E get(int i) {
+        return (E)AA.getVolatile(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setVolatile}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, E newValue) {
+        AA.setVolatile(array, i, newValue);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, E newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code
+     * newValue} and returns the old value,
+     * with memory effects as specified by {@link VarHandle#getAndSet}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final E getAndSet(int i, E newValue) {
+        return (E)AA.getAndSet(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#compareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, E expectedValue, E newValue) {
+        return AA.compareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @deprecated This method has plain memory effects but the method
+     * name implies volatile memory effects (see methods such as
+     * {@link #compareAndExchange} and {@link #compareAndSet}).  To avoid
+     * confusion over plain or volatile memory effects it is recommended that
+     * the method {@link #weakCompareAndSetPlain} be used instead.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @see #weakCompareAndSetPlain
+     */
+    @Deprecated(since="9")
+    public final boolean weakCompareAndSet(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by {@link VarHandle#weakCompareAndSetPlain}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetPlain(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetPlain(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * previous value. The function should be side-effect-free, since
+     * it may be re-applied when attempted updates fail due to
+     * contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function, returning the
+     * updated value. The function should be side-effect-free, since it
+     * may be re-applied when attempted updates fail due to contention
+     * among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = updateFunction.apply(prev);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndAccumulate(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return prev;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the element at index {@code i} with
+     * the results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value of the element at index {@code i}
+     * as its first argument, and the given update as the second
+     * argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E accumulateAndGet(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        E prev = get(i), next = null;
+        for (boolean haveNext = false;;) {
+            if (!haveNext)
+                next = accumulatorFunction.apply(prev, x);
+            if (weakCompareAndSetVolatile(i, prev, next))
+                return next;
+            haveNext = (prev == (prev = get(i)));
+        }
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(get(i));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // 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);
+        @SuppressWarnings("removal")
+        Field arrayField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = AtomicReferenceArray.class
+                        .getDeclaredField("array");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
+        try {
+            arrayField.set(this, a);
+        } catch (IllegalAccessException e) {
+            throw new Error(e);
+        }
+    }
+
+    // jdk9
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory semantics of reading as if the variable was declared
+     * non-{@code volatile}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getPlain(int i) {
+        return (E)AA.get(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory semantics of setting as if the variable was
+     * declared non-{@code volatile} and non-{@code final}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setPlain(int i, E newValue) {
+        AA.set(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getOpaque}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getOpaque(int i) {
+        return (E)AA.getOpaque(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setOpaque}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setOpaque(int i, E newValue) {
+        AA.setOpaque(array, i, newValue);
+    }
+
+    /**
+     * Returns the current value of the element at index {@code i},
+     * with memory effects as specified by {@link VarHandle#getAcquire}.
+     *
+     * @param i the index
+     * @return the value
+     * @since 9
+     */
+    public final E getAcquire(int i) {
+        return (E)AA.getAcquire(array, i);
+    }
+
+    /**
+     * Sets the element at index {@code i} to {@code newValue},
+     * with memory effects as specified by {@link VarHandle#setRelease}.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 9
+     */
+    public final void setRelease(int i, E newValue) {
+        AA.setRelease(array, i, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchange}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchange(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchange(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchangeAcquire(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Atomically sets the element at index {@code i} to {@code newValue}
+     * if the element's current value, referred to as the <em>witness
+     * value</em>, {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#compareAndExchangeRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return the witness value, which will be the same as the
+     * expected value if successful
+     * @since 9
+     */
+    public final E compareAndExchangeRelease(int i, E expectedValue, E newValue) {
+        return (E)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSet}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetVolatile(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSet(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetAcquire}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+    }
+
+    /**
+     * Possibly atomically sets the element at index {@code i} to
+     * {@code newValue} if the element's current value {@code == expectedValue},
+     * with memory effects as specified by
+     * {@link VarHandle#weakCompareAndSetRelease}.
+     *
+     * @param i the index
+     * @param expectedValue the expected value
+     * @param newValue the new value
+     * @return {@code true} if successful
+     * @since 9
+     */
+    public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) {
+        return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/android-35/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
new file mode 100644
index 0000000..0cbe3e7
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -0,0 +1,490 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.reflect.CallerSensitive;
+import jdk.internal.reflect.Reflection;
+import java.lang.invoke.VarHandle;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile} reference fields of designated
+ * classes.  This class is designed for use in atomic data structures
+ * in which several reference fields of the same node are
+ * independently subject to atomic updates. For example, a tree node
+ * might be declared as
+ *
+ * <pre> {@code
+ * class Node {
+ *   private volatile Node left, right;
+ *
+ *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
+ *   private static final AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
+ *
+ *   Node getLeft() { return left; }
+ *   boolean compareAndSetLeft(Node expect, Node update) {
+ *     return leftUpdater.compareAndSet(this, expect, update);
+ *   }
+ *   // ... and so on
+ * }}</pre>
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ * @param <V> The type of the field
+ */
+public abstract class AtomicReferenceFieldUpdater<T,V> {
+
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class arguments are needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param vclass the class of the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @param <W> the type of instances of vclass
+     * @return the updater
+     * @throws ClassCastException if the field is of the wrong type
+     * @throws IllegalArgumentException if the field is not volatile
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
+                                                                    Class<W> vclass,
+                                                                    String fieldName) {
+        return new AtomicReferenceFieldUpdaterImpl<U,W>
+            (tclass, vclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicReferenceFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean compareAndSet(T obj, V expect, V update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p>This operation may fail spuriously and does not provide
+     * ordering guarantees, so is only rarely an appropriate
+     * alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean weakCompareAndSet(T obj, V expect, V update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, V newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, V newValue);
+
+    /**
+     * Returns the current value held in the field of the given object
+     * managed by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract V get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public V getAndSet(T obj, V newValue) {
+        V prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given
+     * function, returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the previous value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates (with memory effects as specified by {@link
+     * VarHandle#compareAndSet}) the field of the given object managed
+     * by this updater with the results of applying the given function
+     * to the current and given values, returning the updated value.
+     * The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among
+     * threads.  The function is applied with the current value as its
+     * first argument, and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class AtomicReferenceFieldUpdaterImpl<T,V>
+        extends AtomicReferenceFieldUpdater<T,V> {
+        private static final Unsafe U = Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+        /** field value type */
+        private final Class<V> vclass;
+
+        /*
+         * Internal type checks within all update methods contain
+         * internal inlined optimizations checking for the common
+         * cases where the class is final (in which case a simple
+         * getClass comparison suffices) or is of type Object (in
+         * which case no check is needed because all objects are
+         * instances of Object). The Object case is handled simply by
+         * setting vclass to null in constructor.  The targetCheck and
+         * updateCheck methods are invoked when these faster
+         * screenings fail.
+         */
+
+        @SuppressWarnings("removal")
+        AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
+                                        final Class<V> vclass,
+                                        final String fieldName,
+                                        final Class<?> caller) {
+            final Field field;
+            final Class<?> fieldClass;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                fieldClass = field.getType();
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (vclass != fieldClass)
+                throw new ClassCastException();
+            if (vclass.isPrimitive())
+                throw new IllegalArgumentException("Must be reference type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
+            this.tclass = tclass;
+            this.vclass = vclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // Android-removed: isAncestor's only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+
+        /**
+         * Returns true if the two classes have the same class loader and
+         * package qualifier
+         */
+        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+            return class1.getClassLoader() == class2.getClassLoader()
+                   && class1.getPackageName() == class2.getPackageName();
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        private final void valueCheck(V v) {
+            if (v != null && !(vclass.isInstance(v)))
+                throwCCE();
+        }
+
+        static void throwCCE() {
+            throw new ClassCastException();
+        }
+
+        public final boolean compareAndSet(T obj, V expect, V update) {
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSetReference(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, V expect, V update) {
+            // same implementation as strong form for now
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSetReference(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putReferenceVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putReferenceRelease(obj, offset, newValue);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V get(T obj) {
+            accessCheck(obj);
+            return (V)U.getReferenceVolatile(obj, offset);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V getAndSet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            return (V)U.getAndSetReference(obj, offset, newValue);
+        }
+    }
+}
diff --git a/android-35/java/util/concurrent/atomic/AtomicStampedReference.java b/android-35/java/util/concurrent/atomic/AtomicStampedReference.java
new file mode 100644
index 0000000..b4152c5
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+/**
+ * An {@code AtomicStampedReference} maintains an object reference
+ * along with an integer "stamp", that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains stamped
+ * references by creating internal objects representing "boxed"
+ * [reference, integer] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicStampedReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final int stamp;
+        private Pair(T reference, int stamp) {
+            this.reference = reference;
+            this.stamp = stamp;
+        }
+        static <T> Pair<T> of(T reference, int stamp) {
+            return new Pair<T>(reference, stamp);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicStampedReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialStamp the initial stamp
+     */
+    public AtomicStampedReference(V initialRef, int initialStamp) {
+        pair = Pair.of(initialRef, initialStamp);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the stamp.
+     *
+     * @return the current value of the stamp
+     */
+    public int getStamp() {
+        return pair.stamp;
+    }
+
+    /**
+     * Returns the current values of both the reference and the stamp.
+     * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
+     *
+     * @param stampHolder an array of size of at least one.  On return,
+     * {@code stampHolder[0]} will hold the value of the stamp.
+     * @return the current value of the reference
+     */
+    public V get(int[] stampHolder) {
+        Pair<V> pair = this.pair;
+        stampHolder[0] = pair.stamp;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp to
+     * the given update values if the current reference is {@code ==}
+     * to the expected reference and the current stamp is equal to the
+     * expected stamp. This operation may fail spuriously and does not
+     * provide ordering guarantees, so is only rarely an
+     * appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V   expectedReference,
+                                     V   newReference,
+                                     int expectedStamp,
+                                     int newStamp) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedStamp, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current stamp is equal to the expected stamp.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V   expectedReference,
+                                 V   newReference,
+                                 int expectedStamp,
+                                 int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedStamp == current.stamp &&
+            ((newReference == current.reference &&
+              newStamp == current.stamp) ||
+             casPair(current, Pair.of(newReference, newStamp)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and stamp.
+     *
+     * @param newReference the new value for the reference
+     * @param newStamp the new value for the stamp
+     */
+    public void set(V newReference, int newStamp) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newStamp != current.stamp)
+            this.pair = Pair.of(newReference, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of the stamp to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean attemptStamp(V expectedReference, int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newStamp == current.stamp ||
+             casPair(current, Pair.of(expectedReference, newStamp)));
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle PAIR;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
+                                   Pair.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return PAIR.compareAndSet(this, cmp, val);
+    }
+}
diff --git a/android-35/java/util/concurrent/atomic/DoubleAccumulator.java b/android-35/java/util/concurrent/atomic/DoubleAccumulator.java
new file mode 100644
index 0000000..d04b825
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/DoubleAccumulator.java
@@ -0,0 +1,306 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import static java.lang.Double.doubleToRawLongBits;
+import static java.lang.Double.longBitsToDouble;
+
+import java.io.Serializable;
+import java.util.function.DoubleBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code double}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #doubleValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>The supplied accumulator function should be side-effect-free,
+ * since it may be re-applied when attempted updates fail due to
+ * contention among threads.  For predictable results, the accumulator
+ * function should be commutative and associative within the floating
+ * point tolerance required in usage contexts. The function is applied
+ * with an existing value (or identity) as one argument, and a given
+ * update as the other argument. For example, to maintain a running
+ * maximum value, you could supply {@code Double::max} along with
+ * {@code Double.NEGATIVE_INFINITY} as the identity. The order of
+ * accumulation within or across threads is not guaranteed. Thus, this
+ * class may not be applicable if numerical stability is required,
+ * especially when combining values of substantially different orders
+ * of magnitude.
+ *
+ * <p>Class {@link DoubleAdder} provides analogs of the functionality
+ * of this class for the common special case of maintaining sums.  The
+ * call {@code new DoubleAdder()} is equivalent to {@code new
+ * DoubleAccumulator((x, y) -> x + y, 0.0)}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    @SuppressWarnings("serial") // Not statically typed as Serializable
+    private final DoubleBinaryOperator function;
+    private final long identity; // use long representation
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction,
+                             double identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = doubleToRawLongBits(identity);
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(double x) {
+        Cell[] cs; long b, v, r; int m; Cell c;
+        if ((cs = cells) != null
+            || ((r = doubleToRawLongBits
+                (function.applyAsDouble(longBitsToDouble(b = base), x))) != b
+                && !casBase(b, r))) {
+            int index = getProbe();
+            boolean uncontended = true;
+            if (cs == null
+                || (m = cs.length - 1) < 0
+                || (c = cs[index & m]) == null
+                || !(uncontended =
+                     ((r = doubleToRawLongBits
+                       (function.applyAsDouble
+                        (longBitsToDouble(v = c.value), x))) == v)
+                     || c.cas(v, r)))
+                doubleAccumulate(x, function, uncontended, index);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public double get() {
+        Cell[] cs = cells;
+        double result = longBitsToDouble(base);
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    result = function.applyAsDouble
+                        (result, longBitsToDouble(c.value));
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] cs = cells;
+        base = identity;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    c.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public double getThenReset() {
+        Cell[] cs = cells;
+        double result = longBitsToDouble(getAndSetBase(identity));
+        if (cs != null) {
+            for (Cell c : cs) {
+                if (c != null) {
+                    double v = longBitsToDouble(c.getAndSet(identity));
+                    result = function.applyAsDouble(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Double.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public double doubleValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code long}
+     * after a narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final double value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        private final DoubleBinaryOperator function;
+
+        /**
+         * The identity value, represented as a long, as converted by
+         * {@link Double#doubleToRawLongBits}.  The original identity
+         * can be recovered using {@link Double#longBitsToDouble}.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(double value,
+                           DoubleBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code DoubleAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            double d = longBitsToDouble(identity);
+            DoubleAccumulator a = new DoubleAccumulator(function, d);
+            a.base = doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="{@docRoot}/serialized-form.html#java.util.concurrent.atomic.DoubleAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/DoubleAdder.java b/android-35/java/util/concurrent/atomic/DoubleAdder.java
new file mode 100644
index 0000000..70a714e
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/DoubleAdder.java
@@ -0,0 +1,263 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code double} sum.  When updates (method {@link #add}) are
+ * contended across threads, the set of variables may grow dynamically
+ * to reduce contention.  Method {@link #sum} (or, equivalently {@link
+ * #doubleValue}) returns the current total combined across the
+ * variables maintaining the sum. The order of accumulation within or
+ * across threads is not guaranteed. Thus, this class may not be
+ * applicable if numerical stability is required, especially when
+ * combining values of substantially different orders of magnitude.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /*
+     * Note that we must use "long" for underlying representations,
+     * because there is no compareAndSet for double, due to the fact
+     * that the bitwise equals used in any CAS implementation is not
+     * the same as double-precision equals.  However, we use CAS only
+     * to detect and alleviate contention, for which bitwise equals
+     * works best anyway. In principle, the long/double conversions
+     * used here should be essentially free on most platforms since
+     * they just re-interpret bits.
+     */
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public DoubleAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(double x) {
+        Cell[] cs; long b, v; int m; Cell c;
+        if ((cs = cells) != null ||
+            !casBase(b = base,
+                     Double.doubleToRawLongBits
+                     (Double.longBitsToDouble(b) + x))) {
+            int index = getProbe();
+            boolean uncontended = true;
+            if (cs == null || (m = cs.length - 1) < 0 ||
+                (c = cs[index & m]) == null ||
+                !(uncontended = c.cas(v = c.value,
+                                      Double.doubleToRawLongBits
+                                      (Double.longBitsToDouble(v) + x))))
+                doubleAccumulate(x, null, uncontended, index);
+        }
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.  Also, because floating-point arithmetic is not
+     * strictly associative, the returned result need not be identical
+     * to the value that would be obtained in a sequential series of
+     * updates to a single variable.
+     *
+     * @return the sum
+     */
+    public double sum() {
+        Cell[] cs = cells;
+        double sum = Double.longBitsToDouble(base);
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    sum += Double.longBitsToDouble(c.value);
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] cs = cells;
+        base = 0L; // relies on fact that double 0 must have same rep as long
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    c.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public double sumThenReset() {
+        Cell[] cs = cells;
+        double sum = Double.longBitsToDouble(getAndSetBase(0L));
+        if (cs != null) {
+            for (Cell c : cs) {
+                if (c != null)
+                    sum += Double.longBitsToDouble(c.getAndSet(0L));
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Double.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public double doubleValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code long} after a
+     * narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a
+     * narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final double value;
+
+        SerializationProxy(DoubleAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code DoubleAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            DoubleAdder a = new DoubleAdder();
+            a.base = Double.doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="{@docRoot}/serialized-form.html#java.util.concurrent.atomic.DoubleAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/LongAccumulator.java b/android-35/java/util/concurrent/atomic/LongAccumulator.java
new file mode 100644
index 0000000..be96853
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/LongAccumulator.java
@@ -0,0 +1,297 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code long}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #longValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common value that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>The order of accumulation within or across threads is not
+ * guaranteed and cannot be depended upon, so this class is only
+ * applicable to functions for which the order of accumulation does
+ * not matter. The supplied accumulator function should be
+ * side-effect-free, since it may be re-applied when attempted updates
+ * fail due to contention among threads. For predictable results, the
+ * accumulator function should be associative and commutative. The
+ * function is applied with an existing value (or identity) as one
+ * argument, and a given update as the other argument.  For example,
+ * to maintain a running maximum value, you could supply {@code
+ * Long::max} along with {@code Long.MIN_VALUE} as the identity.
+ *
+ * <p>Class {@link LongAdder} provides analogs of the functionality of
+ * this class for the common special case of maintaining counts and
+ * sums.  The call {@code new LongAdder()} is equivalent to {@code new
+ * LongAccumulator((x, y) -> x + y, 0L)}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    @SuppressWarnings("serial") // Not statically typed as Serializable
+    private final LongBinaryOperator function;
+    private final long identity;
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public LongAccumulator(LongBinaryOperator accumulatorFunction,
+                           long identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = identity;
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(long x) {
+        Cell[] cs; long b, v, r; int m; Cell c;
+        if ((cs = cells) != null
+            || ((r = function.applyAsLong(b = base, x)) != b
+                && !casBase(b, r))) {
+            int index = getProbe();
+            boolean uncontended = true;
+            if (cs == null
+                || (m = cs.length - 1) < 0
+                || (c = cs[index & m]) == null
+                || !(uncontended =
+                     (r = function.applyAsLong(v = c.value, x)) == v
+                     || c.cas(v, r)))
+                longAccumulate(x, function, uncontended, index);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public long get() {
+        Cell[] cs = cells;
+        long result = base;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    result = function.applyAsLong(result, c.value);
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] cs = cells;
+        base = identity;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    c.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public long getThenReset() {
+        Cell[] cs = cells;
+        long result = getAndSetBase(identity);
+        if (cs != null) {
+            for (Cell c : cs) {
+                if (c != null) {
+                    long v = c.getAndSet(identity);
+                    result = function.applyAsLong(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code double}
+     * after a widening primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final long value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        @SuppressWarnings("serial") // Not statically typed as Serializable
+        private final LongBinaryOperator function;
+
+        /**
+         * The identity value.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(long value,
+                           LongBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code LongAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAccumulator a = new LongAccumulator(function, identity);
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="{@docRoot}/serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/LongAdder.java b/android-35/java/util/concurrent/atomic/LongAdder.java
new file mode 100644
index 0000000..c069249
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/LongAdder.java
@@ -0,0 +1,265 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code long} sum.  When updates (method {@link #add}) are contended
+ * across threads, the set of variables may grow dynamically to reduce
+ * contention. Method {@link #sum} (or, equivalently, {@link
+ * #longValue}) returns the current total combined across the
+ * variables maintaining the sum.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common sum that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>LongAdders can be used with a {@link
+ * java.util.concurrent.ConcurrentHashMap} to maintain a scalable
+ * frequency map (a form of histogram or multiset). For example, to
+ * add a count to a {@code ConcurrentHashMap<String,LongAdder> freqs},
+ * initializing if not already present, you can use {@code
+ * freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public LongAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(long x) {
+        Cell[] cs; long b, v; int m; Cell c;
+        if ((cs = cells) != null || !casBase(b = base, b + x)) {
+            int index = getProbe();
+            boolean uncontended = true;
+            if (cs == null || (m = cs.length - 1) < 0 ||
+                (c = cs[index & m]) == null ||
+                !(uncontended = c.cas(v = c.value, v + x)))
+                longAccumulate(x, null, uncontended, index);
+        }
+    }
+
+    /**
+     * Equivalent to {@code add(1)}.
+     */
+    public void increment() {
+        add(1L);
+    }
+
+    /**
+     * Equivalent to {@code add(-1)}.
+     */
+    public void decrement() {
+        add(-1L);
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.
+     *
+     * @return the sum
+     */
+    public long sum() {
+        Cell[] cs = cells;
+        long sum = base;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    sum += c.value;
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] cs = cells;
+        base = 0L;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    c.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public long sumThenReset() {
+        Cell[] cs = cells;
+        long sum = getAndSetBase(0L);
+        if (cs != null) {
+            for (Cell c : cs) {
+                if (c != null)
+                    sum += c.getAndSet(0L);
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Long.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public long longValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a narrowing
+     * primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code double} after a widening
+     * primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final long value;
+
+        SerializationProxy(LongAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code LongAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAdder a = new LongAdder();
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="{@docRoot}/serialized-form.html#java.util.concurrent.atomic.LongAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/Striped64.java b/android-35/java/util/concurrent/atomic/Striped64.java
new file mode 100644
index 0000000..3b9925a
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/Striped64.java
@@ -0,0 +1,407 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * A package-local class holding common representation and mechanics
+ * for classes supporting dynamic striping on 64bit values. The class
+ * extends Number so that concrete subclasses must publicly do so.
+ */
+@SuppressWarnings({"removal","serial"})
+abstract class Striped64 extends Number {
+    /*
+     * This class maintains a lazily-initialized table of atomically
+     * updated variables, plus an extra "base" field. The table size
+     * is a power of two. Indexing uses masked per-thread hash codes.
+     * Nearly all declarations in this class are package-private,
+     * accessed directly by subclasses.
+     *
+     * Table entries are of class Cell; a variant of AtomicLong padded
+     * (via @Contended) to reduce cache contention. Padding is
+     * overkill for most Atomics because they are usually irregularly
+     * scattered in memory and thus don't interfere much with each
+     * other. But Atomic objects residing in arrays will tend to be
+     * placed adjacent to each other, and so will most often share
+     * cache lines (with a huge negative performance impact) without
+     * this precaution.
+     *
+     * In part because Cells are relatively large, we avoid creating
+     * them until they are needed.  When there is no contention, all
+     * updates are made to the base field.  Upon first contention (a
+     * failed CAS on base update), the table is initialized to size 2.
+     * The table size is doubled upon further contention until
+     * reaching the nearest power of two greater than or equal to the
+     * number of CPUS. Table slots remain empty (null) until they are
+     * needed.
+     *
+     * A single spinlock ("cellsBusy") is used for initializing and
+     * resizing the table, as well as populating slots with new Cells.
+     * There is no need for a blocking lock; when the lock is not
+     * available, threads try other slots (or the base).  During these
+     * retries, there is increased contention and reduced locality,
+     * which is still better than alternatives.
+     *
+     * The Thread probe fields maintained via ThreadLocalRandom serve
+     * as per-thread hash codes. We let them remain uninitialized as
+     * zero (if they come in this way) until they contend at slot
+     * 0. They are then initialized to values that typically do not
+     * often conflict with others.  Contention and/or table collisions
+     * are indicated by failed CASes when performing an update
+     * operation. Upon a collision, if the table size is less than
+     * the capacity, it is doubled in size unless some other thread
+     * holds the lock. If a hashed slot is empty, and lock is
+     * available, a new Cell is created. Otherwise, if the slot
+     * exists, a CAS is tried.  Retries proceed by "double hashing",
+     * using a secondary hash (Marsaglia XorShift) to try to find a
+     * free slot.
+     *
+     * The table size is capped because, when there are more threads
+     * than CPUs, supposing that each thread were bound to a CPU,
+     * there would exist a perfect hash function mapping threads to
+     * slots that eliminates collisions. When we reach capacity, we
+     * search for this mapping by randomly varying the hash codes of
+     * colliding threads.  Because search is random, and collisions
+     * only become known via CAS failures, convergence can be slow,
+     * and because threads are typically not bound to CPUS forever,
+     * may not occur at all. However, despite these limitations,
+     * observed contention rates are typically low in these cases.
+     *
+     * It is possible for a Cell to become unused when threads that
+     * once hashed to it terminate, as well as in the case where
+     * doubling the table causes no thread to hash to it under
+     * expanded mask.  We do not try to detect or remove such cells,
+     * under the assumption that for long-running instances, observed
+     * contention levels will recur, so the cells will eventually be
+     * needed again; and for short-lived ones, it does not matter.
+     */
+
+    /**
+     * Padded variant of AtomicLong supporting only raw accesses plus CAS.
+     *
+     * JVM intrinsics note: It would be possible to use a release-only
+     * form of CAS here, if it were provided.
+     */
+    @jdk.internal.vm.annotation.Contended
+    static final class Cell {
+        volatile long value;
+        Cell(long x) { value = x; }
+        final boolean cas(long cmp, long val) {
+            return VALUE.weakCompareAndSetRelease(this, cmp, val);
+        }
+        final void reset() {
+            VALUE.setVolatile(this, 0L);
+        }
+        final void reset(long identity) {
+            VALUE.setVolatile(this, identity);
+        }
+        final long getAndSet(long val) {
+            return (long)VALUE.getAndSet(this, val);
+        }
+
+        // VarHandle mechanics
+        private static final VarHandle VALUE;
+        static {
+            try {
+                MethodHandles.Lookup l = MethodHandles.lookup();
+                VALUE = l.findVarHandle(Cell.class, "value", long.class);
+            } catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+    }
+
+    /** Number of CPUS, to place bound on table size */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Table of cells. When non-null, size is a power of 2.
+     */
+    transient volatile Cell[] cells;
+
+    /**
+     * Base value, used mainly when there is no contention, but also as
+     * a fallback during table initialization races. Updated via CAS.
+     */
+    transient volatile long base;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating Cells.
+     */
+    transient volatile int cellsBusy;
+
+    /**
+     * Package-private default constructor.
+     */
+    Striped64() {
+    }
+
+    /**
+     * CASes the base field.
+     */
+    final boolean casBase(long cmp, long val) {
+        return BASE.weakCompareAndSetRelease(this, cmp, val);
+    }
+
+    final long getAndSetBase(long val) {
+        return (long)BASE.getAndSet(this, val);
+    }
+
+    /**
+     * CASes the cellsBusy field from 0 to 1 to acquire lock.
+     */
+    final boolean casCellsBusy() {
+        return CELLSBUSY.compareAndSet(this, 0, 1);
+    }
+
+    /**
+     * Returns the probe value for the current thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int getProbe() {
+        return (int) THREAD_PROBE.get(Thread.currentThread());
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        THREAD_PROBE.set(Thread.currentThread(), probe);
+        return probe;
+    }
+
+    /**
+     * Handles cases of updates involving initialization, resizing,
+     * creating new Cells, and/or contention. See above for
+     * explanation. This method suffers the usual non-modularity
+     * problems of optimistic retry code, relying on rechecked sets of
+     * reads.
+     *
+     * @param x the value
+     * @param fn the update function, or null for add (this convention
+     * avoids the need for an extra field or function in LongAdder).
+     * @param wasUncontended false if CAS failed before call
+     * @param index thread index from getProbe
+     */
+    final void longAccumulate(long x, LongBinaryOperator fn,
+                              boolean wasUncontended, int index) {
+        if (index == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            index = getProbe();
+            wasUncontended = true;
+        }
+        for (boolean collide = false;;) {       // True if last slot nonempty
+            Cell[] cs; Cell c; int n; long v;
+            if ((cs = cells) != null && (n = cs.length) > 0) {
+                if ((c = cs[(n - 1) & index]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(x);   // Optimistically create
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & index] == null) {
+                                    rs[j] = r;
+                                    break;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (c.cas(v = c.value,
+                               (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                    break;
+                else if (n >= NCPU || cells != cs)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == cs)        // Expand table unless stale
+                            cells = Arrays.copyOf(cs, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                index = advanceProbe(index);
+            }
+            else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == cs) {
+                        Cell[] rs = new Cell[2];
+                        rs[index & 1] = new Cell(x);
+                        cells = rs;
+                        break;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base,
+                             (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                break;
+        }
+    }
+
+    private static long apply(DoubleBinaryOperator fn, long v, double x) {
+        double d = Double.longBitsToDouble(v);
+        d = (fn == null) ? d + x : fn.applyAsDouble(d, x);
+        return Double.doubleToRawLongBits(d);
+    }
+
+    /**
+     * Same as longAccumulate, but injecting long/double conversions
+     * in too many places to sensibly merge with long version, given
+     * the low-overhead requirements of this class. So must instead be
+     * maintained by copy/paste/adapt.
+     */
+    final void doubleAccumulate(double x, DoubleBinaryOperator fn,
+                                boolean wasUncontended, int index) {
+        if (index == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            index = getProbe();
+            wasUncontended = true;
+        }
+        for (boolean collide = false;;) {       // True if last slot nonempty
+            Cell[] cs; Cell c; int n; long v;
+            if ((cs = cells) != null && (n = cs.length) > 0) {
+                if ((c = cs[(n - 1) & index]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(Double.doubleToRawLongBits(x));
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & index] == null) {
+                                    rs[j] = r;
+                                    break;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (c.cas(v = c.value, apply(fn, v, x)))
+                    break;
+                else if (n >= NCPU || cells != cs)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == cs)        // Expand table unless stale
+                            cells = Arrays.copyOf(cs, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                index = advanceProbe(index);
+            }
+            else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == cs) {
+                        Cell[] rs = new Cell[2];
+                        rs[index & 1] = new Cell(Double.doubleToRawLongBits(x));
+                        cells = rs;
+                        break;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base, apply(fn, v, x)))
+                break;
+        }
+    }
+
+    // VarHandle mechanics
+    private static final VarHandle BASE;
+    private static final VarHandle CELLSBUSY;
+    private static final VarHandle THREAD_PROBE;
+    static {
+        try {
+            MethodHandles.Lookup l = MethodHandles.lookup();
+            BASE = l.findVarHandle(Striped64.class,
+                    "base", long.class);
+            CELLSBUSY = l.findVarHandle(Striped64.class,
+                    "cellsBusy", int.class);
+            l = java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<>() {
+                        public MethodHandles.Lookup run() {
+                            try {
+                                return MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
+                            } catch (ReflectiveOperationException e) {
+                                throw new ExceptionInInitializerError(e);
+                            }
+                        }});
+            THREAD_PROBE = l.findVarHandle(Thread.class,
+                    "threadLocalRandomProbe", int.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+}
diff --git a/android-35/java/util/concurrent/atomic/package-info.java b/android-35/java/util/concurrent/atomic/package-info.java
new file mode 100644
index 0000000..ef3c08b
--- /dev/null
+++ b/android-35/java/util/concurrent/atomic/package-info.java
@@ -0,0 +1,111 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * A small toolkit of classes that support lock-free thread-safe
+ * programming on single variables.  Instances of Atomic classes
+ * maintain values that are accessed and updated using methods
+ * otherwise available for fields using associated atomic {@link
+ * java.lang.invoke.VarHandle} operations.
+ *
+ * <p>Instances of classes
+ * {@link java.util.concurrent.atomic.AtomicBoolean},
+ * {@link java.util.concurrent.atomic.AtomicInteger},
+ * {@link java.util.concurrent.atomic.AtomicLong}, and
+ * {@link java.util.concurrent.atomic.AtomicReference}
+ * each provide access and updates to a single variable of the
+ * corresponding type.  Each class also provides appropriate utility
+ * methods for that type.  For example, classes {@code AtomicLong} and
+ * {@code AtomicInteger} provide atomic increment methods.  One
+ * application is to generate sequence numbers, as in:
+ *
+ * <pre> {@code
+ * class Sequencer {
+ *   private final AtomicLong sequenceNumber
+ *     = new AtomicLong(17);
+ *   public long next() {
+ *     return sequenceNumber.getAndIncrement();
+ *   }
+ * }}</pre>
+ *
+ * <p>Arbitrary transformations of the contained value are provided both
+ * by low-level read-modify-write operations such as {@code compareAndSet}
+ * and by higher-level methods such as {@code getAndUpdate}.
+ *
+ * <p>These classes are not general purpose replacements for {@code
+ * java.lang.Integer} and related classes.  They do <em>not</em>
+ * define methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo}.  Because atomic variables are expected to be mutated,
+ * they are poor choices for hash table keys.
+ *
+ * <p>The
+ * {@link java.util.concurrent.atomic.AtomicIntegerArray},
+ * {@link java.util.concurrent.atomic.AtomicLongArray}, and
+ * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
+ * further extend atomic operation support to arrays of these types.
+ * These classes are also notable in providing {@code volatile} access
+ * semantics for their array elements.
+ *
+ * <p>In addition to classes representing single values and arrays,
+ * this package contains <em>Updater</em> classes that can be used to
+ * obtain {@code compareAndSet} and related operations on any selected
+ * {@code volatile} field of any selected class. These classes
+ * predate the introduction of {@link
+ * java.lang.invoke.VarHandle}, and are of more limited use.
+ * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
+ * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
+ * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
+ * reflection-based utilities that provide access to the associated
+ * field types.  These are mainly of use in atomic data structures in
+ * which several {@code volatile} fields of the same node (for
+ * example, the links of a tree node) are independently subject to
+ * atomic updates.  These classes enable greater flexibility in how
+ * and when to use atomic updates, at the expense of more awkward
+ * reflection-based setup, less convenient usage, and weaker
+ * guarantees.
+ *
+ * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
+ * class associates a single boolean with a reference.  For example, this
+ * bit might be used inside a data structure to mean that the object
+ * being referenced has logically been deleted.
+ *
+ * The {@link java.util.concurrent.atomic.AtomicStampedReference}
+ * class associates an integer value with a reference.  This may be
+ * used for example, to represent version numbers corresponding to
+ * series of updates.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.atomic;
diff --git a/android-35/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/android-35/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
new file mode 100644
index 0000000..30dec97
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A synchronizer that may be exclusively owned by a thread.  This
+ * class provides a basis for creating locks and related synchronizers
+ * that may entail a notion of ownership.  The
+ * {@code AbstractOwnableSynchronizer} class itself does not manage or
+ * use this information. However, subclasses and tools may use
+ * appropriately maintained values to help control and monitor access
+ * and provide diagnostics.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    /** Use serial ID even though all fields transient. */
+    private static final long serialVersionUID = 3737899427754241961L;
+
+    /**
+     * Empty constructor for use by subclasses.
+     */
+    protected AbstractOwnableSynchronizer() { }
+
+    /**
+     * The current owner of exclusive mode synchronization.
+     */
+    private transient Thread exclusiveOwnerThread;
+
+    /**
+     * Sets the thread that currently owns exclusive access.
+     * A {@code null} argument indicates that no thread owns access.
+     * This method does not otherwise impose any synchronization or
+     * {@code volatile} field accesses.
+     * @param thread the owner thread
+     */
+    protected final void setExclusiveOwnerThread(Thread thread) {
+        exclusiveOwnerThread = thread;
+    }
+
+    /**
+     * Returns the thread last set by {@code setExclusiveOwnerThread},
+     * or {@code null} if never set.  This method does not otherwise
+     * impose any synchronization or {@code volatile} field accesses.
+     * @return the owner thread
+     */
+    protected final Thread getExclusiveOwnerThread() {
+        return exclusiveOwnerThread;
+    }
+}
diff --git a/android-35/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/android-35/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
new file mode 100644
index 0000000..829058b
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -0,0 +1,1490 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RejectedExecutionException;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * A version of {@link AbstractQueuedSynchronizer} in
+ * which synchronization state is maintained as a {@code long}.
+ * This class has exactly the same structure, properties, and methods
+ * as {@code AbstractQueuedSynchronizer} with the exception
+ * that all state-related parameters and results are defined
+ * as {@code long} rather than {@code int}. This class
+ * may be useful when creating synchronizers such as
+ * multilevel locks and barriers that require
+ * 64 bits of state.
+ *
+ * <p>See {@link AbstractQueuedSynchronizer} for usage
+ * notes and examples.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedLongSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414692L;
+
+    /**
+     * Constructor for subclasses to call.
+     */
+    // Android-changed: Keep the constructor protected.
+    // public AbstractQueuedLongSynchronizer() {}
+    protected AbstractQueuedLongSynchronizer() {}
+
+    /*
+     * To keep sources in sync, the remainder of this source file is
+     * exactly cloned from AbstractQueuedSynchronizer, replacing class
+     * name and changing ints related with sync state to longs. Please
+     * keep it that way.
+     */
+
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
+
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
+
+        /**
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
+         */
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park();
+            return true;
+        }
+    }
+
+    /**
+     * Head of the wait queue, lazily initialized.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue. After initialization, modified only via casTail.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile long state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final long getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(long newState) {
+        state = newState;
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(long expect, long update) {
+        return U.compareAndSetLong(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
+     */
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
+                }
+            }
+        }
+    }
+
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
+    /**
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
+     *
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
+     */
+    final int acquire(Node node, long arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
+
+        for (;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
+                }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
+     */
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
+        }
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
+        }
+        return 0;
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected long tryAcquireShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a {@link ConditionObject} method.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    public final void acquire(long arg) {
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(long arg)
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
+            throw new InterruptedException();
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(long arg, long nanosTimeout)
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    public final boolean release(long arg) {
+        if (tryRelease(arg)) {
+            signalNext(head);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(long arg) {
+        if (tryAcquireShared(arg) < 0)
+            acquire(null, arg, true, false, false, 0L);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(long arg)
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
+            throw new InterruptedException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    public final boolean releaseShared(long arg) {
+        if (tryReleaseShared(arg)) {
+            signalNext(head);
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        for (Node p = tail, h = head; p != h && p != null; p = p.prev)
+            if (p.status >= 0)
+                return true;
+        return false;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
+        }
+        return first;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.waiter == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * 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}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(long arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
+    }
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.waiter != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.waiter;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link AbstractQueuedLongSynchronizer}
+     * serving as the basis of a {@link Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedLongSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient ConditionNode firstWaiter;
+        /** Last node of condition queue. */
+        private transient ConditionNode lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Signalling methods
+
+        /**
+         * Removes and transfers one or all waiters to sync queue.
+         */
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
+                first = next;
+            }
+        }
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            ConditionNode first = firstWaiter;
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            if (first != null)
+                doSignal(first, false);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            ConditionNode first = firstWaiter;
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            if (first != null)
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private long enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                long savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, rejected = false;
+            while (!canReacquire(node)) {
+                if (Thread.interrupted())
+                    interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        if (rejected)
+                            node.block();
+                        else
+                            ForkJoinPool.managedBlock(node);
+                    } catch (RejectedExecutionException ex) {
+                        rejected = true;
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
+            }
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false, rejected = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        if (rejected)
+                            node.block();
+                        else
+                            ForkJoinPool.managedBlock(node);
+                    } catch (RejectedExecutionException ex) {
+                        rejected = true;
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
+            }
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) {
+            return sync == AbstractQueuedLongSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "tail");
+
+    static {
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/android-35/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
new file mode 100644
index 0000000..921150f
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -0,0 +1,1856 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RejectedExecutionException;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Provides a framework for implementing blocking locks and related
+ * synchronizers (semaphores, events, etc) that rely on
+ * first-in-first-out (FIFO) wait queues.  This class is designed to
+ * be a useful basis for most kinds of synchronizers that rely on a
+ * single atomic {@code int} value to represent state. Subclasses
+ * must define the protected methods that change this state, and which
+ * define what that state means in terms of this object being acquired
+ * or released.  Given these, the other methods in this class carry
+ * out all queuing and blocking mechanics. Subclasses can maintain
+ * other state fields, but only the atomically updated {@code int}
+ * value manipulated using methods {@link #getState}, {@link
+ * #setState} and {@link #compareAndSetState} is tracked with respect
+ * to synchronization.
+ *
+ * <p>Subclasses should be defined as non-public internal helper
+ * classes that are used to implement the synchronization properties
+ * of their enclosing class.  Class
+ * {@code AbstractQueuedSynchronizer} does not implement any
+ * synchronization interface.  Instead it defines methods such as
+ * {@link #acquireInterruptibly} that can be invoked as
+ * appropriate by concrete locks and related synchronizers to
+ * implement their public methods.
+ *
+ * <p>This class supports either or both a default <em>exclusive</em>
+ * mode and a <em>shared</em> mode. When acquired in exclusive mode,
+ * attempted acquires by other threads cannot succeed. Shared mode
+ * acquires by multiple threads may (but need not) succeed. This class
+ * does not &quot;understand&quot; these differences except in the
+ * mechanical sense that when a shared mode acquire succeeds, the next
+ * waiting thread (if one exists) must also determine whether it can
+ * acquire as well. Threads waiting in the different modes share the
+ * same FIFO queue. Usually, implementation subclasses support only
+ * one of these modes, but both can come into play for example in a
+ * {@link ReadWriteLock}. Subclasses that support only exclusive or
+ * only shared modes need not define the methods supporting the unused mode.
+ *
+ * <p>This class defines a nested {@link ConditionObject} class that
+ * can be used as a {@link Condition} implementation by subclasses
+ * supporting exclusive mode for which method {@link
+ * #isHeldExclusively} reports whether synchronization is exclusively
+ * held with respect to the current thread, method {@link #release}
+ * invoked with the current {@link #getState} value fully releases
+ * this object, and {@link #acquire}, given this saved state value,
+ * eventually restores this object to its previous acquired state.  No
+ * {@code AbstractQueuedSynchronizer} method otherwise creates such a
+ * condition, so if this constraint cannot be met, do not use it.  The
+ * behavior of {@link ConditionObject} depends of course on the
+ * semantics of its synchronizer implementation.
+ *
+ * <p>This class provides inspection, instrumentation, and monitoring
+ * methods for the internal queue, as well as similar methods for
+ * condition objects. These can be exported as desired into classes
+ * using an {@code AbstractQueuedSynchronizer} for their
+ * synchronization mechanics.
+ *
+ * <p>Serialization of this class stores only the underlying atomic
+ * integer maintaining state, so deserialized objects have empty
+ * thread queues. Typical subclasses requiring serializability will
+ * define a {@code readObject} method that restores this to a known
+ * initial state upon deserialization.
+ *
+ * <h2>Usage</h2>
+ *
+ * <p>To use this class as the basis of a synchronizer, redefine the
+ * following methods, as applicable, by inspecting and/or modifying
+ * the synchronization state using {@link #getState}, {@link
+ * #setState} and/or {@link #compareAndSetState}:
+ *
+ * <ul>
+ * <li>{@link #tryAcquire}
+ * <li>{@link #tryRelease}
+ * <li>{@link #tryAcquireShared}
+ * <li>{@link #tryReleaseShared}
+ * <li>{@link #isHeldExclusively}
+ * </ul>
+ *
+ * Each of these methods by default throws {@link
+ * UnsupportedOperationException}.  Implementations of these methods
+ * must be internally thread-safe, and should in general be short and
+ * not block. Defining these methods is the <em>only</em> supported
+ * means of using this class. All other methods are declared
+ * {@code final} because they cannot be independently varied.
+ *
+ * <p>You may also find the inherited methods from {@link
+ * AbstractOwnableSynchronizer} useful to keep track of the thread
+ * owning an exclusive synchronizer.  You are encouraged to use them
+ * -- this enables monitoring and diagnostic tools to assist users in
+ * determining which threads hold locks.
+ *
+ * <p>Even though this class is based on an internal FIFO queue, it
+ * does not automatically enforce FIFO acquisition policies.  The core
+ * of exclusive synchronization takes the form:
+ *
+ * <pre>
+ * <em>Acquire:</em>
+ *     while (!tryAcquire(arg)) {
+ *        <em>enqueue thread if it is not already queued</em>;
+ *        <em>possibly block current thread</em>;
+ *     }
+ *
+ * <em>Release:</em>
+ *     if (tryRelease(arg))
+ *        <em>unblock the first queued thread</em>;
+ * </pre>
+ *
+ * (Shared mode is similar but may involve cascading signals.)
+ *
+ * <p id="barging">Because checks in acquire are invoked before
+ * enqueuing, a newly acquiring thread may <em>barge</em> ahead of
+ * others that are blocked and queued.  However, you can, if desired,
+ * define {@code tryAcquire} and/or {@code tryAcquireShared} to
+ * disable barging by internally invoking one or more of the inspection
+ * methods, thereby providing a <em>fair</em> FIFO acquisition order.
+ * In particular, most fair synchronizers can define {@code tryAcquire}
+ * to return {@code false} if {@link #hasQueuedPredecessors} (a method
+ * specifically designed to be used by fair synchronizers) returns
+ * {@code true}.  Other variations are possible.
+ *
+ * <p>Throughput and scalability are generally highest for the
+ * default barging (also known as <em>greedy</em>,
+ * <em>renouncement</em>, and <em>convoy-avoidance</em>) strategy.
+ * While this is not guaranteed to be fair or starvation-free, earlier
+ * queued threads are allowed to recontend before later queued
+ * threads, and each recontention has an unbiased chance to succeed
+ * against incoming threads.  Also, while acquires do not
+ * &quot;spin&quot; in the usual sense, they may perform multiple
+ * invocations of {@code tryAcquire} interspersed with other
+ * computations before blocking.  This gives most of the benefits of
+ * spins when exclusive synchronization is only briefly held, without
+ * most of the liabilities when it isn't. If so desired, you can
+ * augment this by preceding calls to acquire methods with
+ * "fast-path" checks, possibly prechecking {@link #hasContended}
+ * and/or {@link #hasQueuedThreads} to only do so if the synchronizer
+ * is likely not to be contended.
+ *
+ * <p>This class provides an efficient and scalable basis for
+ * synchronization in part by specializing its range of use to
+ * synchronizers that can rely on {@code int} state, acquire, and
+ * release parameters, and an internal FIFO wait queue. When this does
+ * not suffice, you can build synchronizers from a lower level using
+ * {@link java.util.concurrent.atomic atomic} classes, your own custom
+ * {@link java.util.Queue} classes, and {@link LockSupport} blocking
+ * support.
+ *
+ * <h2>Usage Examples</h2>
+ *
+ * <p>Here is a non-reentrant mutual exclusion lock class that uses
+ * the value zero to represent the unlocked state, and one to
+ * represent the locked state. While a non-reentrant lock
+ * does not strictly require recording of the current owner
+ * thread, this class does so anyway to make usage easier to monitor.
+ * It also supports conditions and exposes some instrumentation methods:
+ *
+ * <pre> {@code
+ * class Mutex implements Lock, java.io.Serializable {
+ *
+ *   // Our internal helper class
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     // Acquires the lock if state is zero
+ *     public boolean tryAcquire(int acquires) {
+ *       assert acquires == 1; // Otherwise unused
+ *       if (compareAndSetState(0, 1)) {
+ *         setExclusiveOwnerThread(Thread.currentThread());
+ *         return true;
+ *       }
+ *       return false;
+ *     }
+ *
+ *     // Releases the lock by setting state to zero
+ *     protected boolean tryRelease(int releases) {
+ *       assert releases == 1; // Otherwise unused
+ *       if (!isHeldExclusively())
+ *         throw new IllegalMonitorStateException();
+ *       setExclusiveOwnerThread(null);
+ *       setState(0);
+ *       return true;
+ *     }
+ *
+ *     // Reports whether in locked state
+ *     public boolean isLocked() {
+ *       return getState() != 0;
+ *     }
+ *
+ *     public boolean isHeldExclusively() {
+ *       // a data race, but safe due to out-of-thin-air guarantees
+ *       return getExclusiveOwnerThread() == Thread.currentThread();
+ *     }
+ *
+ *     // Provides a Condition
+ *     public Condition newCondition() {
+ *       return new ConditionObject();
+ *     }
+ *
+ *     // Deserializes properly
+ *     private void readObject(ObjectInputStream s)
+ *         throws IOException, ClassNotFoundException {
+ *       s.defaultReadObject();
+ *       setState(0); // reset to unlocked state
+ *     }
+ *   }
+ *
+ *   // The sync object does all the hard work. We just forward to it.
+ *   private final Sync sync = new Sync();
+ *
+ *   public void lock()              { sync.acquire(1); }
+ *   public boolean tryLock()        { return sync.tryAcquire(1); }
+ *   public void unlock()            { sync.release(1); }
+ *   public Condition newCondition() { return sync.newCondition(); }
+ *   public boolean isLocked()       { return sync.isLocked(); }
+ *   public boolean isHeldByCurrentThread() {
+ *     return sync.isHeldExclusively();
+ *   }
+ *   public boolean hasQueuedThreads() {
+ *     return sync.hasQueuedThreads();
+ *   }
+ *   public void lockInterruptibly() throws InterruptedException {
+ *     sync.acquireInterruptibly(1);
+ *   }
+ *   public boolean tryLock(long timeout, TimeUnit unit)
+ *       throws InterruptedException {
+ *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+ *   }
+ * }}</pre>
+ *
+ * <p>Here is a latch class that is like a
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * except that it only requires a single {@code signal} to
+ * fire. Because a latch is non-exclusive, it uses the {@code shared}
+ * acquire and release methods.
+ *
+ * <pre> {@code
+ * class BooleanLatch {
+ *
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     boolean isSignalled() { return getState() != 0; }
+ *
+ *     protected int tryAcquireShared(int ignore) {
+ *       return isSignalled() ? 1 : -1;
+ *     }
+ *
+ *     protected boolean tryReleaseShared(int ignore) {
+ *       setState(1);
+ *       return true;
+ *     }
+ *   }
+ *
+ *   private final Sync sync = new Sync();
+ *   public boolean isSignalled() { return sync.isSignalled(); }
+ *   public void signal()         { sync.releaseShared(1); }
+ *   public void await() throws InterruptedException {
+ *     sync.acquireSharedInterruptibly(1);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414691L;
+
+    /**
+     * Creates a new {@code AbstractQueuedSynchronizer} instance
+     * with initial synchronization state of zero.
+     */
+    protected AbstractQueuedSynchronizer() { }
+
+    /*
+     * Overview.
+     *
+     * The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * Hagersten) lock queue. CLH locks are normally used for
+     * spinlocks.  We instead use them for blocking synchronizers by
+     * including explicit ("prev" and "next") links plus a "status"
+     * field that allow nodes to signal successors when releasing
+     * locks, and handle cancellation due to interrupts and timeouts.
+     * The status field includes bits that track whether a thread
+     * needs a signal (using LockSupport.unpark). Despite these
+     * additions, we maintain most CLH locality properties.
+     *
+     * To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you set the head field, so the next eligible
+     * waiter becomes first.
+     *
+     *  +------+  prev +-------+       +------+
+     *  | head | <---- | first | <---- | tail |
+     *  +------+       +-------+       +------+
+     *
+     * Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple point of demarcation
+     * from unqueued to queued. The "next" link of the predecessor is
+     * set by the enqueuing thread after successful CAS. Even though
+     * non-atomic, this suffices to ensure that any blocked thread is
+     * signalled by a predecessor when eligible (although in the case
+     * of cancellation, possibly with the assistance of a signal in
+     * method cleanQueue). Signalling is based in part on a
+     * Dekker-like scheme in which the to-be waiting thread indicates
+     * WAITING status, then retries acquiring, and then rechecks
+     * status before blocking. The signaller atomically clears WAITING
+     * status when unparking.
+     *
+     * Dequeuing on acquire involves detaching (nulling) a node's
+     * "prev" node and then updating the "head". Other threads check
+     * if a node is or was dequeued by checking "prev" rather than
+     * head. We enforce the nulling then setting order by spin-waiting
+     * if necessary. Because of this, the lock algorithm is not itself
+     * strictly "lock-free" because an acquiring thread may need to
+     * wait for a previous acquire to make progress. When used with
+     * exclusive locks, such progress is required anyway. However
+     * Shared mode may (uncommonly) require a spin-wait before
+     * setting head field to ensure proper propagation. (Historical
+     * note: This allows some simplifications and efficiencies
+     * compared to previous versions of this class.)
+     *
+     * A node's predecessor can change due to cancellation while it is
+     * waiting, until the node is first in queue, at which point it
+     * cannot change. The acquire methods cope with this by rechecking
+     * "prev" before waiting. The prev and next fields are modified
+     * only via CAS by cancelled nodes in method cleanQueue. The
+     * unsplice strategy is reminiscent of Michael-Scott queues in
+     * that after a successful CAS to prev field, other threads help
+     * fix next fields.  Because cancellation often occurs in bunches
+     * that complicate decisions about necessary signals, each call to
+     * cleanQueue traverses the queue until a clean sweep. Nodes that
+     * become relinked as first are unconditionally unparked
+     * (sometimes unnecessarily, but those cases are not worth
+     * avoiding).
+     *
+     * A thread may try to acquire if it is first (frontmost) in the
+     * queue, and sometimes before.  Being first does not guarantee
+     * success; it only gives the right to contend. We balance
+     * throughput, overhead, and fairness by allowing incoming threads
+     * to "barge" and acquire the synchronizer while in the process of
+     * enqueuing, in which case an awakened first thread may need to
+     * rewait.  To counteract possible repeated unlucky rewaits, we
+     * exponentially increase retries (up to 256) to acquire each time
+     * a thread is unparked. Except in this case, AQS locks do not
+     * spin; they instead interleave attempts to acquire with
+     * bookkeeping steps. (Users who want spinlocks can use
+     * tryAcquire.)
+     *
+     * To improve garbage collectibility, fields of nodes not yet on
+     * list are null. (It is not rare to create and then throw away a
+     * node without using it.) Fields of nodes coming off the list are
+     * nulled out as soon as possible. This accentuates the challenge
+     * of externally determining the first waiting thread (as in
+     * method getFirstQueuedThread). This sometimes requires the
+     * fallback of traversing backwards from the atomically updated
+     * "tail" when fields appear null. (This is never needed in the
+     * process of signalling though.)
+     *
+     * CLH queues need a dummy header node to get started. But
+     * we don't create them on construction, because it would be wasted
+     * effort if there is never contention. Instead, the node
+     * is constructed and head and tail pointers are set upon first
+     * contention.
+     *
+     * Shared mode operations differ from Exclusive in that an acquire
+     * signals the next waiter to try to acquire if it is also
+     * Shared. The tryAcquireShared API allows users to indicate the
+     * degree of propagation, but in most applications, it is more
+     * efficient to ignore this, allowing the successor to try
+     * acquiring in any case.
+     *
+     * Threads waiting on Conditions use nodes with an additional
+     * link to maintain the (FIFO) list of conditions. Conditions only
+     * need to link nodes in simple (non-concurrent) linked queues
+     * because they are only accessed when exclusively held.  Upon
+     * await, a node is inserted into a condition queue.  Upon signal,
+     * the node is enqueued on the main queue.  A special status field
+     * value is used to track and atomically trigger this.
+     *
+     * Accesses to fields head, tail, and state use full Volatile
+     * mode, along with CAS. Node fields status, prev and next also do
+     * so while threads may be signallable, but sometimes use weaker
+     * modes otherwise. Accesses to field "waiter" (the thread to be
+     * signalled) are always sandwiched between other atomic accesses
+     * so are used in Plain mode. We use jdk.internal Unsafe versions
+     * of atomic access methods rather than VarHandles to avoid
+     * potential VM bootstrap issues.
+     *
+     * Most of the above is performed by primary internal method
+     * acquire, that is invoked in some way by all exported acquire
+     * methods.  (It is usually easy for compilers to optimize
+     * call-site specializations when heavily used.)
+     *
+     * There are several arbitrary decisions about when and how to
+     * check interrupts in both acquire and await before and/or after
+     * blocking. The decisions are less arbitrary in implementation
+     * updates because some users appear to rely on original behaviors
+     * in ways that are racy and so (rarely) wrong in general but hard
+     * to justify changing.
+     *
+     * Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Scherer and Michael Scott, along with members of JSR-166
+     * expert group, for helpful ideas, discussions, and critiques
+     * on the design of this class.
+     */
+
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
+
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
+
+        /**
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
+         */
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park();
+            return true;
+        }
+    }
+
+    /**
+     * Head of the wait queue, lazily initialized.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue. After initialization, modified only via casTail.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile int state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final int getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(int newState) {
+        state = newState;
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(int expect, int update) {
+        return U.compareAndSetInt(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
+     */
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
+                }
+            }
+        }
+    }
+
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
+    /**
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
+     *
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
+     */
+    final int acquire(Node node, int arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
+
+        for (;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
+                }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
+     */
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
+        }
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
+        }
+        return 0;
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected int tryAcquireShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a {@link ConditionObject} method.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    public final void acquire(int arg) {
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(int arg)
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
+            throw new InterruptedException();
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    public final boolean release(int arg) {
+        if (tryRelease(arg)) {
+            signalNext(head);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(int arg) {
+        if (tryAcquireShared(arg) < 0)
+            acquire(null, arg, true, false, false, 0L);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(int arg)
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
+            throw new InterruptedException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    public final boolean releaseShared(int arg) {
+        if (tryReleaseShared(arg)) {
+            signalNext(head);
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        for (Node p = tail, h = head; p != h && p != null; p = p.prev)
+            if (p.status >= 0)
+                return true;
+        return false;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
+        }
+        return first;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.waiter == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * 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}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
+    }
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.waiter != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.waiter;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link AbstractQueuedSynchronizer}
+     * serving as the basis of a {@link Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient ConditionNode firstWaiter;
+        /** Last node of condition queue. */
+        private transient ConditionNode lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Signalling methods
+
+        /**
+         * Removes and transfers one or all waiters to sync queue.
+         */
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
+                first = next;
+            }
+        }
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            ConditionNode first = firstWaiter;
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            if (first != null)
+                doSignal(first, false);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            ConditionNode first = firstWaiter;
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            if (first != null)
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private int enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                int savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, rejected = false;
+            while (!canReacquire(node)) {
+                if (Thread.interrupted())
+                    interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        if (rejected)
+                            node.block();
+                        else
+                            ForkJoinPool.managedBlock(node);
+                    } catch (RejectedExecutionException ex) {
+                        rejected = true;
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
+            }
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false, rejected = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        if (rejected)
+                            node.block();
+                        else
+                            ForkJoinPool.managedBlock(node);
+                    } catch (RejectedExecutionException ex) {
+                        rejected = true;
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
+            }
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
+            return sync == AbstractQueuedSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "tail");
+
+    static {
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/locks/Condition.java b/android-35/java/util/concurrent/locks/Condition.java
new file mode 100644
index 0000000..455ded8
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/Condition.java
@@ -0,0 +1,490 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Condition} factors out the {@code Object} monitor
+ * methods ({@link Object#wait() wait}, {@link Object#notify notify}
+ * and {@link Object#notifyAll notifyAll}) into distinct objects to
+ * give the effect of having multiple wait-sets per object, by
+ * combining them with the use of arbitrary {@link Lock} implementations.
+ * Where a {@code Lock} replaces the use of {@code synchronized} methods
+ * and statements, a {@code Condition} replaces the use of the Object
+ * monitor methods.
+ *
+ * <p>Conditions (also known as <em>condition queues</em> or
+ * <em>condition variables</em>) provide a means for one thread to
+ * suspend execution (to &quot;wait&quot;) until notified by another
+ * thread that some state condition may now be true.  Because access
+ * to this shared state information occurs in different threads, it
+ * must be protected, so a lock of some form is associated with the
+ * condition. The key property that waiting for a condition provides
+ * is that it <em>atomically</em> releases the associated lock and
+ * suspends the current thread, just like {@code Object.wait}.
+ *
+ * <p>A {@code Condition} instance is intrinsically bound to a lock.
+ * To obtain a {@code Condition} instance for a particular {@link Lock}
+ * instance use its {@link Lock#newCondition newCondition()} method.
+ *
+ * <p>As an example, suppose we have a bounded buffer which supports
+ * {@code put} and {@code take} methods.  If a
+ * {@code take} is attempted on an empty buffer, then the thread will block
+ * until an item becomes available; if a {@code put} is attempted on a
+ * full buffer, then the thread will block until a space becomes available.
+ * We would like to keep waiting {@code put} threads and {@code take}
+ * threads in separate wait-sets so that we can use the optimization of
+ * only notifying a single thread at a time when items or spaces become
+ * available in the buffer. This can be achieved using two
+ * {@link Condition} instances.
+ * <pre>
+ * class BoundedBuffer&lt;E&gt; {
+ *   <b>final Lock lock = new ReentrantLock();</b>
+ *   final Condition notFull  = <b>lock.newCondition(); </b>
+ *   final Condition notEmpty = <b>lock.newCondition(); </b>
+ *
+ *   final Object[] items = new Object[100];
+ *   int putptr, takeptr, count;
+ *
+ *   public void put(E x) throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == items.length)
+ *         <b>notFull.await();</b>
+ *       items[putptr] = x;
+ *       if (++putptr == items.length) putptr = 0;
+ *       ++count;
+ *       <b>notEmpty.signal();</b>
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ *
+ *   public E take() throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == 0)
+ *         <b>notEmpty.await();</b>
+ *       E x = (E) items[takeptr];
+ *       if (++takeptr == items.length) takeptr = 0;
+ *       --count;
+ *       <b>notFull.signal();</b>
+ *       return x;
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ * }
+ * </pre>
+ *
+ * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides
+ * this functionality, so there is no reason to implement this
+ * sample usage class.)
+ *
+ * <p>A {@code Condition} implementation can provide behavior and semantics
+ * that is
+ * different from that of the {@code Object} monitor methods, such as
+ * guaranteed ordering for notifications, or not requiring a lock to be held
+ * when performing notifications.
+ * If an implementation provides such specialized semantics then the
+ * implementation must document those semantics.
+ *
+ * <p>Note that {@code Condition} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement,
+ * and can have their own monitor {@link Object#wait wait} and
+ * {@link Object#notify notify} methods invoked.
+ * Acquiring the monitor lock of a {@code Condition} instance, or using its
+ * monitor methods, has no specified relationship with acquiring the
+ * {@link Lock} associated with that {@code Condition} or the use of its
+ * {@linkplain #await waiting} and {@linkplain #signal signalling} methods.
+ * It is recommended that to avoid confusion you never use {@code Condition}
+ * instances in this way, except perhaps within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any parameter
+ * will result in a {@link NullPointerException} being thrown.
+ *
+ * <h2>Implementation Considerations</h2>
+ *
+ * <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
+ * wakeup</em>&quot; is permitted to occur, in
+ * general, as a concession to the underlying platform semantics.
+ * This has little practical impact on most application programs as a
+ * {@code Condition} should always be waited upon in a loop, testing
+ * the state predicate that is being waited for.  An implementation is
+ * free to remove the possibility of spurious wakeups but it is
+ * recommended that applications programmers always assume that they can
+ * occur and so always wait in a loop.
+ *
+ * <p>The three forms of condition waiting
+ * (interruptible, non-interruptible, and timed) may differ in their ease of
+ * implementation on some platforms and in their performance characteristics.
+ * In particular, it may be difficult to provide these features and maintain
+ * specific semantics such as ordering guarantees.
+ * Further, the ability to interrupt the actual suspension of the thread may
+ * not always be feasible to implement on all platforms.
+ *
+ * <p>Consequently, an implementation is not required to define exactly the
+ * same guarantees or semantics for all three forms of waiting, nor is it
+ * required to support interruption of the actual suspension of the thread.
+ *
+ * <p>An implementation is required to
+ * clearly document the semantics and guarantees provided by each of the
+ * waiting methods, and when an implementation does support interruption of
+ * thread suspension then it must obey the interruption semantics as defined
+ * in this interface.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action that may have
+ * unblocked the thread. An implementation should document this behavior.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Condition {
+
+    /**
+     * Causes the current thread to wait until it is signalled or
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>The lock associated with this {@code Condition} is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of four things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal. In that case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    void await() throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread's interrupted status is set when it enters
+     * this method, or it is {@linkplain Thread#interrupt interrupted}
+     * while waiting, it will continue to wait until signalled. When it finally
+     * returns from this method its interrupted status will still
+     * be set.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     */
+    void awaitUninterruptibly();
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified waiting time elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p>The method returns an estimate of the number of nanoseconds
+     * remaining to wait given the supplied {@code nanosTimeout}
+     * value upon return, or a value less than or equal to zero if it
+     * timed out. This value can be used to determine whether and how
+     * long to re-wait in cases where the wait returns but an awaited
+     * condition still does not hold. Typical uses of this method take
+     * the following form:
+     *
+     * <pre> {@code
+     * boolean aMethod(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
+     *   long nanosRemaining = unit.toNanos(timeout);
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (nanosRemaining <= 0L)
+     *         return false;
+     *       nanosRemaining = theCondition.awaitNanos(nanosRemaining);
+     *     }
+     *     // ...
+     *     return true;
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p>Design note: This method requires a nanosecond argument so
+     * as to avoid truncation errors in reporting remaining times.
+     * Such precision loss would make it difficult for programmers to
+     * ensure that total waiting times are not systematically shorter
+     * than specified when re-waits occur.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the elapse
+     * of the specified waiting time. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param nanosTimeout the maximum time to wait, in nanoseconds
+     * @return an estimate of the {@code nanosTimeout} value minus
+     *         the time spent waiting upon return from this method.
+     *         A positive value may be used as the argument to a
+     *         subsequent call to this method to finish waiting out
+     *         the desired time.  A value less than or equal to zero
+     *         indicates that no time remains.
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    long awaitNanos(long nanosTimeout) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses. This method is behaviorally
+     * 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
+     *         before return from the method, else {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean await(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified deadline elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified deadline elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p>The return value indicates whether the deadline has elapsed,
+     * which can be used as follows:
+     * <pre> {@code
+     * boolean aMethod(Date deadline)
+     *     throws InterruptedException {
+     *   boolean stillWaiting = true;
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (!stillWaiting)
+     *         return false;
+     *       stillWaiting = theCondition.awaitUntil(deadline);
+     *     }
+     *     // ...
+     *     return true;
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the passing
+     * of the specified deadline. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param deadline the absolute time to wait until
+     * @return {@code false} if the deadline has elapsed upon return, else
+     *         {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean awaitUntil(Date deadline) throws InterruptedException;
+
+    /**
+     * Wakes up one waiting thread.
+     *
+     * <p>If any threads are waiting on this condition then one
+     * is selected for waking up. That thread must then re-acquire the
+     * lock before returning from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signal();
+
+    /**
+     * Wakes up all waiting threads.
+     *
+     * <p>If any threads are waiting on this condition then they are
+     * all woken up. Each thread must re-acquire the lock before it can
+     * return from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signalAll();
+}
diff --git a/android-35/java/util/concurrent/locks/Lock.java b/android-35/java/util/concurrent/locks/Lock.java
new file mode 100644
index 0000000..84100e6
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/Lock.java
@@ -0,0 +1,359 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Lock} implementations provide more extensive locking
+ * operations than can be obtained using {@code synchronized} methods
+ * and statements.  They allow more flexible structuring, may have
+ * quite different properties, and may support multiple associated
+ * {@link Condition} objects.
+ *
+ * <p>A lock is a tool for controlling access to a shared resource by
+ * multiple threads. Commonly, a lock provides exclusive access to a
+ * shared resource: only one thread at a time can acquire the lock and
+ * all access to the shared resource requires that the lock be
+ * acquired first. However, some locks may allow concurrent access to
+ * a shared resource, such as the read lock of a {@link ReadWriteLock}.
+ *
+ * <p>The use of {@code synchronized} methods or statements provides
+ * access to the implicit monitor lock associated with every object, but
+ * forces all lock acquisition and release to occur in a block-structured way:
+ * when multiple locks are acquired they must be released in the opposite
+ * order, and all locks must be released in the same lexical scope in which
+ * they were acquired.
+ *
+ * <p>While the scoping mechanism for {@code synchronized} methods
+ * and statements makes it much easier to program with monitor locks,
+ * and helps avoid many common programming errors involving locks,
+ * there are occasions where you need to work with locks in a more
+ * flexible way. For example, some algorithms for traversing
+ * concurrently accessed data structures require the use of
+ * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
+ * acquire the lock of node A, then node B, then release A and acquire
+ * C, then release B and acquire D and so on.  Implementations of the
+ * {@code Lock} interface enable the use of such techniques by
+ * allowing a lock to be acquired and released in different scopes,
+ * and allowing multiple locks to be acquired and released in any
+ * order.
+ *
+ * <p>With this increased flexibility comes additional
+ * responsibility. The absence of block-structured locking removes the
+ * automatic release of locks that occurs with {@code synchronized}
+ * methods and statements. In most cases, the following idiom
+ * should be used:
+ *
+ * <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
+ * held is protected by try-finally or try-catch to ensure that the
+ * lock is released when necessary.
+ *
+ * <p>{@code Lock} implementations provide additional functionality
+ * over the use of {@code synchronized} methods and statements by
+ * providing a non-blocking attempt to acquire a lock ({@link
+ * #tryLock()}), an attempt to acquire the lock that can be
+ * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
+ * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).
+ *
+ * <p>A {@code Lock} class can also provide behavior and semantics
+ * that is quite different from that of the implicit monitor lock,
+ * such as guaranteed ordering, non-reentrant usage, or deadlock
+ * detection. If an implementation provides such specialized semantics
+ * then the implementation must document those semantics.
+ *
+ * <p>Note that {@code Lock} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement.
+ * Acquiring the
+ * monitor lock of a {@code Lock} instance has no specified relationship
+ * with invoking any of the {@link #lock} methods of that instance.
+ * It is recommended that to avoid confusion you never use {@code Lock}
+ * instances in this way, except within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any
+ * parameter will result in a {@link NullPointerException} being
+ * thrown.
+ *
+ * <h2>Memory Synchronization</h2>
+ *
+ * <p>All {@code Lock} implementations <em>must</em> enforce the same
+ * memory synchronization semantics as provided by the built-in monitor
+ * lock, as described in
+ * Chapter 17 of
+ * <cite>The Java Language Specification</cite>:
+ * <ul>
+ * <li>A successful {@code lock} operation has the same memory
+ * synchronization effects as a successful <em>Lock</em> action.
+ * <li>A successful {@code unlock} operation has the same
+ * memory synchronization effects as a successful <em>Unlock</em> action.
+ * </ul>
+ *
+ * Unsuccessful locking and unlocking operations, and reentrant
+ * locking/unlocking operations, do not require any memory
+ * synchronization effects.
+ *
+ * <h2>Implementation Considerations</h2>
+ *
+ * <p>The three forms of lock acquisition (interruptible,
+ * non-interruptible, and timed) may differ in their performance
+ * characteristics, ordering guarantees, or other implementation
+ * qualities.  Further, the ability to interrupt the <em>ongoing</em>
+ * acquisition of a lock may not be available in a given {@code Lock}
+ * class.  Consequently, an implementation is not required to define
+ * exactly the same guarantees or semantics for all three forms of
+ * lock acquisition, nor is it required to support interruption of an
+ * ongoing lock acquisition.  An implementation is required to clearly
+ * document the semantics and guarantees provided by each of the
+ * locking methods. It must also obey the interruption semantics as
+ * defined in this interface, to the extent that interruption of lock
+ * acquisition is supported: which is either totally, or only on
+ * method entry.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ * @see ReentrantLock
+ * @see Condition
+ * @see ReadWriteLock
+ * @jls 17.4 Memory Model
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Lock {
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until the
+     * lock has been acquired.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation may be able to detect erroneous use
+     * of the lock, such as an invocation that would cause deadlock, and
+     * may throw an (unchecked) exception in such circumstances.  The
+     * circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     */
+    void lock();
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is available and returns immediately.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     *
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the
+     * lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some
+     * implementations may not be possible, and if possible may be an
+     * expensive operation.  The programmer should be aware that this
+     * may be the case. An implementation should document when this is
+     * the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over
+     * normal method return.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would
+     * cause deadlock, and may throw an (unchecked) exception in such
+     * circumstances.  The circumstances and the exception type must
+     * be documented by that {@code Lock} implementation.
+     *
+     * @throws InterruptedException if the current thread is
+     *         interrupted while acquiring the lock (and interruption
+     *         of lock acquisition is supported)
+     */
+    void lockInterruptibly() throws InterruptedException;
+
+    /**
+     * Acquires the lock only if it is free at the time of invocation.
+     *
+     * <p>Acquires the lock if it is available and returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>A typical usage idiom for this method would be:
+     * <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.
+     *
+     * @return {@code true} if the lock was acquired and
+     *         {@code false} otherwise
+     */
+    boolean tryLock();
+
+    /**
+     * Acquires the lock if it is free within the given waiting time and the
+     * current thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the lock is available this method returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported; or
+     * <li>The specified waiting time elapses
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.
+     * If the time is
+     * less than or equal to zero, the method will not wait at all.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some implementations
+     * may not be possible, and if possible may
+     * be an expensive operation.
+     * The programmer should be aware that this may be the case. An
+     * implementation should document when this is the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return, or reporting a timeout.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would cause
+     * deadlock, and may throw an (unchecked) exception in such circumstances.
+     * The circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return {@code true} if the lock was acquired and {@code false}
+     *         if the waiting time elapsed before the lock was acquired
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while acquiring the lock (and interruption of lock
+     *         acquisition is supported)
+     */
+    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Releases the lock.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation will usually impose
+     * restrictions on which thread can release a lock (typically only the
+     * holder of the lock can release it) and may throw
+     * an (unchecked) exception if the restriction is violated.
+     * Any restrictions and the exception
+     * type must be documented by that {@code Lock} implementation.
+     */
+    void unlock();
+
+    /**
+     * Returns a new {@link Condition} instance that is bound to this
+     * {@code Lock} instance.
+     *
+     * <p>Before waiting on the condition the lock must be held by the
+     * current thread.
+     * A call to {@link Condition#await()} will atomically release the lock
+     * before waiting and re-acquire the lock before the wait returns.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The exact operation of the {@link Condition} instance depends on
+     * the {@code Lock} implementation and must be documented by that
+     * implementation.
+     *
+     * @return A new {@link Condition} instance for this {@code Lock} instance
+     * @throws UnsupportedOperationException if this {@code Lock}
+     *         implementation does not support conditions
+     */
+    Condition newCondition();
+}
diff --git a/android-35/java/util/concurrent/locks/LockSupport.java b/android-35/java/util/concurrent/locks/LockSupport.java
new file mode 100644
index 0000000..33767c7
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/LockSupport.java
@@ -0,0 +1,430 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Basic thread blocking primitives for creating locks and other
+ * synchronization classes.
+ *
+ * <p>This class associates, with each thread that uses it, a permit
+ * (in the sense of the {@link java.util.concurrent.Semaphore
+ * Semaphore} class). A call to {@code park} will return immediately
+ * if the permit is available, consuming it in the process; otherwise
+ * it <em>may</em> block.  A call to {@code unpark} makes the permit
+ * available, if it was not already available. (Unlike with Semaphores
+ * though, permits do not accumulate. There is at most one.)
+ * Reliable usage requires the use of volatile (or atomic) variables
+ * to control when to park or unpark.  Orderings of calls to these
+ * methods are maintained with respect to volatile variable accesses,
+ * but not necessarily non-volatile variable accesses.
+ *
+ * <p>Methods {@code park} and {@code unpark} provide efficient
+ * means of blocking and unblocking threads that do not encounter the
+ * problems that cause the deprecated methods {@code Thread.suspend}
+ * and {@code Thread.resume} to be unusable for such purposes: Races
+ * between one thread invoking {@code park} and another thread trying
+ * to {@code unpark} it will preserve liveness, due to the
+ * permit. Additionally, {@code park} will return if the caller's
+ * thread was interrupted, and timeout versions are supported. The
+ * {@code park} method may also return at any other time, for "no
+ * reason", so in general must be invoked within a loop that rechecks
+ * conditions upon return. In this sense {@code park} serves as an
+ * optimization of a "busy wait" that does not waste as much time
+ * spinning, but must be paired with an {@code unpark} to be
+ * effective.
+ *
+ * <p>The three forms of {@code park} each also support a
+ * {@code blocker} object parameter. This object is recorded while
+ * the thread is blocked to permit monitoring and diagnostic tools to
+ * identify the reasons that threads are blocked. (Such tools may
+ * access blockers using method {@link #getBlocker(Thread)}.)
+ * The use of these forms rather than the original forms without this
+ * parameter is strongly encouraged. The normal argument to supply as
+ * a {@code blocker} within a lock implementation is {@code this}.
+ *
+ * <p>These methods are designed to be used as tools for creating
+ * 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> {@code
+ * while (!canProceed()) {
+ *   // ensure request to unpark is visible to other threads
+ *   ...
+ *   LockSupport.park(this);
+ * }}</pre>
+ *
+ * where no actions by the thread publishing a request to unpark,
+ * prior to the call to {@code park}, entail locking or blocking.
+ * Because only one permit is associated with each thread, any
+ * intermediary uses of {@code park}, including implicitly via class
+ * loading, could lead to an unresponsive thread (a "lost unpark").
+ *
+ * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
+ * non-reentrant lock class:
+ * <pre> {@code
+ * class FIFOMutex {
+ *   private final AtomicBoolean locked = new AtomicBoolean(false);
+ *   private final Queue<Thread> waiters
+ *     = new ConcurrentLinkedQueue<>();
+ *
+ *   public void lock() {
+ *     boolean wasInterrupted = false;
+ *     // publish current thread for unparkers
+ *     waiters.add(Thread.currentThread());
+ *
+ *     // Block while not first in queue or cannot acquire lock
+ *     while (waiters.peek() != Thread.currentThread() ||
+ *            !locked.compareAndSet(false, true)) {
+ *       LockSupport.park(this);
+ *       // ignore interrupts while waiting
+ *       if (Thread.interrupted())
+ *         wasInterrupted = true;
+ *     }
+ *
+ *     waiters.remove();
+ *     // ensure correct interrupt status on return
+ *     if (wasInterrupted)
+ *       Thread.currentThread().interrupt();
+ *   }
+ *
+ *   public void unlock() {
+ *     locked.set(false);
+ *     LockSupport.unpark(waiters.peek());
+ *   }
+ *
+ *   static {
+ *     // Reduce the risk of "lost unpark" due to classloading
+ *     Class<?> ensureLoaded = LockSupport.class;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ */
+public class LockSupport {
+    private LockSupport() {} // Cannot be instantiated.
+
+    private static void setBlocker(Thread t, Object arg) {
+        U.putReferenceOpaque(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Sets the object to be returned by invocations of {@link
+     * #getBlocker getBlocker} for the current thread. This method may
+     * be used before invoking the no-argument version of {@link
+     * LockSupport#park() park()} from non-public objects, allowing
+     * more helpful diagnostics, or retaining compatibility with
+     * previous implementations of blocking methods.  Previous values
+     * of the blocker are not automatically restored after blocking.
+     * To obtain the effects of {@code park(b}}, use {@code
+     * setCurrentBlocker(b); park(); setCurrentBlocker(null);}
+     *
+     * @param blocker the blocker object
+     * @since 14
+     */
+    public static void setCurrentBlocker(Object blocker) {
+        U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
+    }
+
+    /**
+     * Makes available the permit for the given thread, if it
+     * was not already available.  If the thread was blocked on
+     * {@code park} then it will unblock.  Otherwise, its next call
+     * to {@code park} is guaranteed not to block. This operation
+     * is not guaranteed to have any effect at all if the given
+     * thread has not been started.
+     *
+     * @param thread the thread to unpark, or {@code null}, in which case
+     *        this operation has no effect
+     */
+    public static void unpark(Thread thread) {
+        if (thread != null)
+            U.unpark(thread);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call returns
+     * immediately; otherwise
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @since 1.6
+     */
+    public static void park(Object blocker) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(false, 0L);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the specified waiting time is zero or negative, the
+     * method does nothing. Otherwise, if the permit is available then
+     * it is consumed and the call returns immediately; otherwise the
+     * current thread becomes disabled for thread scheduling purposes
+     * and lies dormant until one of four things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param nanos the maximum number of nanoseconds to wait
+     * @since 1.6
+     */
+    public static void parkNanos(Object blocker, long nanos) {
+        if (nanos > 0) {
+            Thread t = Thread.currentThread();
+            setBlocker(t, blocker);
+            U.park(false, nanos);
+            setBlocker(t, null);
+        }
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     * @since 1.6
+     */
+    public static void parkUntil(Object blocker, long deadline) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(true, deadline);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Returns the blocker object supplied to the most recent
+     * invocation of a park method that has not yet unblocked, or null
+     * if not blocked.  The value returned is just a momentary
+     * 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 U.getReferenceOpaque(t, PARKBLOCKER);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of three
+     * things happens:
+     *
+     * <ul>
+     *
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     */
+    public static void park() {
+        U.park(false, 0L);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the specified waiting time is zero or negative, the
+     * method does nothing. Otherwise, if the permit is available then
+     * it is consumed and the call returns immediately; otherwise the
+     * current thread becomes disabled for thread scheduling purposes
+     * and lies dormant until one of four things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param nanos the maximum number of nanoseconds to wait
+     */
+    public static void parkNanos(long nanos) {
+        if (nanos > 0)
+            U.park(false, nanos);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     */
+    public static void parkUntil(long deadline) {
+        U.park(true, deadline);
+    }
+
+    /**
+     * Returns the thread id for the given thread.  We must access
+     * this directly rather than via method Thread.getId() because
+     * getId() has been known to be overridden in ways that do not
+     * preserve unique mappings.
+     */
+    static final long getThreadId(Thread thread) {
+        return U.getLong(thread, TID);
+    }
+
+    // Hotspot implementation via intrinsics API
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long PARKBLOCKER
+        = U.objectFieldOffset(Thread.class, "parkBlocker");
+    private static final long TID
+        = U.objectFieldOffset(Thread.class, "tid");
+
+}
diff --git a/android-35/java/util/concurrent/locks/ReadWriteLock.java b/android-35/java/util/concurrent/locks/ReadWriteLock.java
new file mode 100644
index 0000000..8455944
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/ReadWriteLock.java
@@ -0,0 +1,132 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A {@code ReadWriteLock} maintains a pair of associated {@link
+ * Lock locks}, one for read-only operations and one for writing.
+ * The {@linkplain #readLock read lock} may be held simultaneously
+ * by multiple reader threads, so long as there are no writers.
+ * The {@linkplain #writeLock write lock} is exclusive.
+ *
+ * <p>All {@code ReadWriteLock} implementations must guarantee that
+ * the memory synchronization effects of {@code writeLock} operations
+ * (as specified in the {@link Lock} interface) also hold with respect
+ * to the associated {@code readLock}. That is, a thread successfully
+ * acquiring the read lock will see all updates made upon previous
+ * release of the write lock.
+ *
+ * <p>A read-write lock allows for a greater level of concurrency in
+ * accessing shared data than that permitted by a mutual exclusion lock.
+ * It exploits the fact that while only a single thread at a time (a
+ * <em>writer</em> thread) can modify the shared data, in many cases any
+ * number of threads can concurrently read the data (hence <em>reader</em>
+ * threads).
+ * In theory, the increase in concurrency permitted by the use of a read-write
+ * lock will lead to performance improvements over the use of a mutual
+ * exclusion lock. In practice this increase in concurrency will only be fully
+ * realized on a multi-processor, and then only if the access patterns for
+ * the shared data are suitable.
+ *
+ * <p>Whether or not a read-write lock will improve performance over the use
+ * of a mutual exclusion lock depends on the frequency that the data is
+ * read compared to being modified, the duration of the read and write
+ * operations, and the contention for the data - that is, the number of
+ * threads that will try to read or write the data at the same time.
+ * For example, a collection that is initially populated with data and
+ * thereafter infrequently modified, while being frequently searched
+ * (such as a directory of some kind) is an ideal candidate for the use of
+ * a read-write lock. However, if updates become frequent then the data
+ * spends most of its time being exclusively locked and there is little, if any
+ * increase in concurrency. Further, if the read operations are too short
+ * the overhead of the read-write lock implementation (which is inherently
+ * more complex than a mutual exclusion lock) can dominate the execution
+ * cost, particularly as many read-write lock implementations still serialize
+ * all threads through a small section of code. Ultimately, only profiling
+ * and measurement will establish whether the use of a read-write lock is
+ * suitable for your application.
+ *
+ * <p>Although the basic operation of a read-write lock is straight-forward,
+ * there are many policy decisions that an implementation must make, which
+ * may affect the effectiveness of the read-write lock in a given application.
+ * Examples of these policies include:
+ * <ul>
+ * <li>Determining whether to grant the read lock or the write lock, when
+ * both readers and writers are waiting, at the time that a writer releases
+ * the write lock. Writer preference is common, as writes are expected to be
+ * short and infrequent. Reader preference is less common as it can lead to
+ * lengthy delays for a write if the readers are frequent and long-lived as
+ * expected. Fair, or &quot;in-order&quot; implementations are also possible.
+ *
+ * <li>Determining whether readers that request the read lock while a
+ * reader is active and a writer is waiting, are granted the read lock.
+ * Preference to the reader can delay the writer indefinitely, while
+ * preference to the writer can reduce the potential for concurrency.
+ *
+ * <li>Determining whether the locks are reentrant: can a thread with the
+ * write lock reacquire it? Can it acquire a read lock while holding the
+ * write lock? Is the read lock itself reentrant?
+ *
+ * <li>Can the write lock be downgraded to a read lock without allowing
+ * an intervening writer? Can a read lock be upgraded to a write lock,
+ * in preference to other waiting readers or writers?
+ *
+ * </ul>
+ * You should consider all of these things when evaluating the suitability
+ * of a given implementation for your application.
+ *
+ * @see ReentrantReadWriteLock
+ * @see Lock
+ * @see ReentrantLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ReadWriteLock {
+    /**
+     * Returns the lock used for reading.
+     *
+     * @return the lock used for reading
+     */
+    Lock readLock();
+
+    /**
+     * Returns the lock used for writing.
+     *
+     * @return the lock used for writing
+     */
+    Lock writeLock();
+}
diff --git a/android-35/java/util/concurrent/locks/ReentrantLock.java b/android-35/java/util/concurrent/locks/ReentrantLock.java
new file mode 100644
index 0000000..c58925b
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/ReentrantLock.java
@@ -0,0 +1,798 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
+
+/**
+ * A reentrant mutual exclusion {@link Lock} with the same basic
+ * behavior and semantics as the implicit monitor lock accessed using
+ * {@code synchronized} methods and statements, but with extended
+ * capabilities.
+ *
+ * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
+ * successfully locking, but not yet unlocking it. A thread invoking
+ * {@code lock} will return, successfully acquiring the lock, when
+ * the lock is not owned by another thread. The method will return
+ * immediately if the current thread already owns the lock. This can
+ * be checked using methods {@link #isHeldByCurrentThread}, and {@link
+ * #getHoldCount}.
+ *
+ * <p>The constructor for this class accepts an optional
+ * <em>fairness</em> parameter.  When set {@code true}, under
+ * contention, locks favor granting access to the longest-waiting
+ * thread.  Otherwise this lock does not guarantee any particular
+ * access order.  Programs using fair locks accessed by many threads
+ * may display lower overall throughput (i.e., are slower; often much
+ * slower) than those using the default setting, but have smaller
+ * variances in times to obtain locks and guarantee lack of
+ * starvation. Note however, that fairness of locks does not guarantee
+ * fairness of thread scheduling. Thus, one of many threads using a
+ * fair lock may obtain it multiple times in succession while other
+ * active threads are not progressing and not currently holding the
+ * lock.
+ * Also note that the untimed {@link #tryLock()} method does not
+ * honor the fairness setting. It will succeed if the lock
+ * is available even if other threads are waiting.
+ *
+ * <p>It is recommended practice to <em>always</em> immediately
+ * follow a call to {@code lock} with a {@code try} block, most
+ * typically in a before/after construction such as:
+ *
+ * <pre> {@code
+ * class X {
+ *   private final ReentrantLock lock = new ReentrantLock();
+ *   // ...
+ *
+ *   public void m() {
+ *     lock.lock();  // block until condition holds
+ *     try {
+ *       // ... method body
+ *     } finally {
+ *       lock.unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>In addition to implementing the {@link Lock} interface, this
+ * class defines a number of {@code public} and {@code protected}
+ * methods for inspecting the state of the lock.  Some of these
+ * methods are only useful for instrumentation and monitoring.
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p>This lock supports a maximum of 2147483647 recursive locks by
+ * the same thread. Attempts to exceed this limit result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantLock implements Lock, java.io.Serializable {
+    private static final long serialVersionUID = 7373984872572414699L;
+    /** Synchronizer providing all implementation mechanics */
+    private final Sync sync;
+
+    /**
+     * Base of synchronization control for this lock. Subclassed
+     * into fair and nonfair versions below. Uses AQS state to
+     * represent the number of holds on the lock.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = -5179523762034025860L;
+
+        /**
+         * Performs non-fair tryLock.
+         */
+        @ReservedStackAccess
+        final boolean tryLock() {
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (compareAndSetState(0, 1)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Checks for reentrancy and acquires if lock immediately
+         * available under fair vs nonfair rules. Locking methods
+         * perform initialTryLock check before relaying to
+         * corresponding AQS acquire methods.
+         */
+        abstract boolean initialTryLock();
+
+        @ReservedStackAccess
+        final void lock() {
+            if (!initialTryLock())
+                acquire(1);
+        }
+
+        @ReservedStackAccess
+        final void lockInterruptibly() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            if (!initialTryLock())
+                acquireInterruptibly(1);
+        }
+
+        @ReservedStackAccess
+        final boolean tryLockNanos(long nanos) throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            return initialTryLock() || tryAcquireNanos(1, nanos);
+        }
+
+        @ReservedStackAccess
+        protected final boolean tryRelease(int releases) {
+            int c = getState() - releases;
+            if (getExclusiveOwnerThread() != Thread.currentThread())
+                throw new IllegalMonitorStateException();
+            boolean free = (c == 0);
+            if (free)
+                setExclusiveOwnerThread(null);
+            setState(c);
+            return free;
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        // Methods relayed from outer class
+
+        final Thread getOwner() {
+            return getState() == 0 ? null : getExclusiveOwnerThread();
+        }
+
+        final int getHoldCount() {
+            return isHeldExclusively() ? getState() : 0;
+        }
+
+        final boolean isLocked() {
+            return getState() != 0;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            setState(0); // reset to unlocked state
+        }
+    }
+
+    /**
+     * Sync object for non-fair locks
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = 7316153563782823691L;
+
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
+            if (compareAndSetState(0, 1)) { // first attempt is unguarded
+                setExclusiveOwnerThread(current);
+                return true;
+            } else if (getExclusiveOwnerThread() == current) {
+                int c = getState() + 1;
+                if (c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            } else
+                return false;
+        }
+
+        /**
+         * Acquire for non-reentrant cases after initialTryLock prescreen
+         */
+        protected final boolean tryAcquire(int acquires) {
+            if (getState() == 0 && compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Sync object for fair locks
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -3000897897090466540L;
+
+        /**
+         * Acquires only if reentrant or queue is empty.
+         */
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Acquires only if thread is first waiter or empty
+         */
+        protected final boolean tryAcquire(int acquires) {
+            if (getState() == 0 && !hasQueuedPredecessors() &&
+                compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock}.
+     * This is equivalent to using {@code ReentrantLock(false)}.
+     */
+    public ReentrantLock() {
+        sync = new NonfairSync();
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock} with the
+     * given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+    }
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds the lock then the hold
+     * count is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until the lock has been acquired,
+     * at which time the lock hold count is set to one.
+     */
+    public void lock() {
+        sync.lock();
+    }
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds this lock then the hold count
+     * is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of two things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread.
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired by the current thread then the lock hold
+     * count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock,
+     *
+     * </ul>
+     *
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void lockInterruptibly() throws InterruptedException {
+        sync.lockInterruptibly();
+    }
+
+    /**
+     * Acquires the lock only if it is not held by another thread at the time
+     * of invocation.
+     *
+     * <p>Acquires the lock if it is not held by another thread and
+     * returns immediately with the value {@code true}, setting the
+     * lock hold count to one. Even when this lock has been set to use a
+     * fair ordering policy, a call to {@code tryLock()} <em>will</em>
+     * immediately acquire the lock if it is available, whether or not
+     * other threads are currently waiting for the lock.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting for this lock, then use
+     * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS)}
+     * which is almost equivalent (it also detects interruption).
+     *
+     * <p>If the current thread already holds this lock then the hold
+     * count is incremented by one and the method returns {@code true}.
+     *
+     * <p>If the lock is held by another thread then this method will return
+     * immediately with the value {@code false}.
+     *
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} otherwise
+     */
+    public boolean tryLock() {
+        return sync.tryLock();
+    }
+
+    /**
+     * Acquires the lock if it is not held by another thread within the given
+     * waiting time and the current thread has not been
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately with the value {@code true}, setting the lock hold count
+     * to one. If this lock has been set to use a fair ordering policy then
+     * an available lock <em>will not</em> be acquired if any other threads
+     * are waiting for the lock. This is in contrast to the {@link #tryLock()}
+     * 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> {@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 {@code true}.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned and
+     * the lock hold count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while
+     * acquiring the lock,
+     *
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock, and
+     * over reporting the elapse of the waiting time.
+     *
+     * @param timeout the time to wait for the lock
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} if the waiting time elapsed before
+     *         the lock could be acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws NullPointerException if the time unit is null
+     */
+    public boolean tryLock(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return sync.tryLockNanos(unit.toNanos(timeout));
+    }
+
+    /**
+     * Attempts to release this lock.
+     *
+     * <p>If the current thread is the holder of this lock then the hold
+     * count is decremented.  If the hold count is now zero then the lock
+     * is released.  If the current thread is not the holder of this
+     * lock then {@link IllegalMonitorStateException} is thrown.
+     *
+     * @throws IllegalMonitorStateException if the current thread does not
+     *         hold this lock
+     */
+    public void unlock() {
+        sync.release(1);
+    }
+
+    /**
+     * Returns a {@link Condition} instance for use with this
+     * {@link Lock} instance.
+     *
+     * <p>The returned {@link Condition} instance supports the same
+     * usages as do the {@link Object} monitor methods ({@link
+     * Object#wait() wait}, {@link Object#notify notify}, and {@link
+     * Object#notifyAll notifyAll}) when used with the built-in
+     * monitor lock.
+     *
+     * <ul>
+     *
+     * <li>If this lock is not held when any of the {@link Condition}
+     * {@linkplain Condition#await() waiting} or {@linkplain
+     * Condition#signal signalling} methods are called, then an {@link
+     * IllegalMonitorStateException} is thrown.
+     *
+     * <li>When the condition {@linkplain Condition#await() waiting}
+     * methods are called the lock is released and, before they
+     * return, the lock is reacquired and the lock hold count restored
+     * to what it was when the method was called.
+     *
+     * <li>If a thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting then the wait will terminate, an {@link
+     * InterruptedException} will be thrown, and the thread's
+     * interrupted status will be cleared.
+     *
+     * <li>Waiting threads are signalled in FIFO order.
+     *
+     * <li>The ordering of lock reacquisition for threads returning
+     * from waiting methods is the same as for threads initially
+     * acquiring the lock, which is in the default case not specified,
+     * but for <em>fair</em> locks favors those threads that have been
+     * waiting the longest.
+     *
+     * </ul>
+     *
+     * @return the Condition object
+     */
+    public Condition newCondition() {
+        return sync.newCondition();
+    }
+
+    /**
+     * Queries the number of holds on this lock by the current thread.
+     *
+     * <p>A thread has a hold on a lock for each lock action that is not
+     * matched by an unlock action.
+     *
+     * <p>The hold count information is typically only used for testing and
+     * debugging purposes. For example, if a certain section of code should
+     * not be entered with the lock already held then we can assert that
+     * fact:
+     *
+     * <pre> {@code
+     * class X {
+     *   final ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *   public void m() {
+     *     assert lock.getHoldCount() == 0;
+     *     lock.lock();
+     *     try {
+     *       // ... method body
+     *     } finally {
+     *       lock.unlock();
+     *     }
+     *   }
+     * }}</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
+     */
+    public int getHoldCount() {
+        return sync.getHoldCount();
+    }
+
+    /**
+     * Queries if this lock is held by the current thread.
+     *
+     * <p>Analogous to the {@link Thread#holdsLock(Object)} method for
+     * built-in monitor locks, this method is typically used for
+     * debugging and testing. For example, a method that should only be
+     * called while a lock is held can assert that this is the case:
+     *
+     * <pre> {@code
+     * class X {
+     *   final ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert lock.isHeldByCurrentThread();
+     *       // ... method body
+     *   }
+     * }}</pre>
+     *
+     * <p>It can also be used to ensure that a reentrant lock is used
+     * in a non-reentrant manner, for example:
+     *
+     * <pre> {@code
+     * class X {
+     *   final ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert !lock.isHeldByCurrentThread();
+     *       lock.lock();
+     *       try {
+     *           // ... method body
+     *       } finally {
+     *           lock.unlock();
+     *       }
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if current thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isHeldByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries if this lock is held by any thread. This method is
+     * designed for use in monitoring of the system state,
+     * not for synchronization control.
+     *
+     * @return {@code true} if any thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isLocked() {
+        return sync.isLocked();
+    }
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns this lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire this lock. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire this lock.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire this
+     * lock. Note that because cancellations may occur at any time, a
+     * {@code true} return does not guarantee that this thread
+     * will ever acquire this lock.  This method is designed primarily for use
+     * in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * this lock.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire this lock.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes either the String {@code "Unlocked"}
+     * or the String {@code "Locked by"} followed by the
+     * {@linkplain Thread#getName name} of the owning thread.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        Thread o = sync.getOwner();
+        return super.toString() + ((o == null) ?
+                                   "[Unlocked]" :
+                                   "[Locked by thread " + o.getName() + "]");
+    }
+}
diff --git a/android-35/java/util/concurrent/locks/ReentrantReadWriteLock.java b/android-35/java/util/concurrent/locks/ReentrantReadWriteLock.java
new file mode 100644
index 0000000..c73bd41
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -0,0 +1,1502 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
+
+/**
+ * An implementation of {@link ReadWriteLock} supporting similar
+ * semantics to {@link ReentrantLock}.
+ * <p>This class has the following properties:
+ *
+ * <ul>
+ * <li><b>Acquisition order</b>
+ *
+ * <p>This class does not impose a reader or writer preference
+ * ordering for lock access.  However, it does support an optional
+ * <em>fairness</em> policy.
+ *
+ * <dl>
+ * <dt><b><i>Non-fair mode (default)</i></b>
+ * <dd>When constructed as non-fair (the default), the order of entry
+ * to the read and write lock is unspecified, subject to reentrancy
+ * constraints.  A nonfair lock that is continuously contended may
+ * indefinitely postpone one or more reader or writer threads, but
+ * will normally have higher throughput than a fair lock.
+ *
+ * <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
+ * 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.
+ *
+ * <p>A thread that tries to acquire a fair read lock (non-reentrantly)
+ * will block if either the write lock is held, or there is a waiting
+ * writer thread. The thread will not acquire the read lock until
+ * after the oldest currently waiting writer thread has acquired and
+ * released the write lock. Of course, if a waiting writer abandons
+ * its wait, leaving one or more reader threads as the longest waiters
+ * in the queue with the write lock free, then those readers will be
+ * assigned the read lock.
+ *
+ * <p>A thread that tries to acquire a fair write lock (non-reentrantly)
+ * 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 immediately acquire the lock
+ * if it is possible, regardless of waiting threads.)
+ * </dl>
+ *
+ * <li><b>Reentrancy</b>
+ *
+ * <p>This lock allows both readers and writers to reacquire read or
+ * write locks in the style of a {@link ReentrantLock}. Non-reentrant
+ * readers are not allowed until all write locks held by the writing
+ * thread have been released.
+ *
+ * <p>Additionally, a writer can acquire the read lock, but not
+ * vice-versa.  Among other applications, reentrancy can be useful
+ * when write locks are held during calls or callbacks to methods that
+ * perform reads under read locks.  If a reader tries to acquire the
+ * write lock it will never succeed.
+ *
+ * <li><b>Lock downgrading</b>
+ * <p>Reentrancy also allows downgrading from the write lock to a read lock,
+ * by acquiring the write lock, then the read lock and then releasing the
+ * write lock. However, upgrading from a read lock to the write lock is
+ * <b>not</b> possible.
+ *
+ * <li><b>Interruption of lock acquisition</b>
+ * <p>The read lock and write lock both support interruption during lock
+ * acquisition.
+ *
+ * <li><b>{@link Condition} support</b>
+ * <p>The write lock provides a {@link Condition} implementation that
+ * behaves in the same way, with respect to the write lock, as the
+ * {@link Condition} implementation provided by
+ * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
+ * This {@link Condition} can, of course, only be used with the write lock.
+ *
+ * <p>The read lock does not support a {@link Condition} and
+ * {@code readLock().newCondition()} throws
+ * {@code UnsupportedOperationException}.
+ *
+ * <li><b>Instrumentation</b>
+ * <p>This class supports methods to determine whether locks
+ * are held or contended. These methods are designed for monitoring
+ * system state, not for synchronization control.
+ * </ul>
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p><b>Sample usages.</b> Here is a code sketch showing how to perform
+ * lock downgrading after updating a cache (exception handling is
+ * particularly tricky when handling multiple locks in a non-nested
+ * fashion):
+ *
+ * <pre> {@code
+ * class CachedData {
+ *   Object data;
+ *   boolean cacheValid;
+ *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *
+ *   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
+ *       }
+ *     }
+ *
+ *     try {
+ *       use(data);
+ *     } finally {
+ *       rwl.readLock().unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * ReentrantReadWriteLocks can be used to improve concurrency in some
+ * uses of some kinds of Collections. This is typically worthwhile
+ * only when the collections are expected to be large, accessed by
+ * more reader threads than writer threads, and entail operations with
+ * overhead that outweighs synchronization overhead. For example, here
+ * is a class using a TreeMap that is expected to be large and
+ * concurrently accessed.
+ *
+ * <pre> {@code
+ * class RWDictionary {
+ *   private final Map<String, Data> m = new TreeMap<>();
+ *   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 List<String> allKeys() {
+ *     r.lock();
+ *     try { return new ArrayList<>(m.keySet()); }
+ *     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>
+ *
+ * <h2>Implementation Notes</h2>
+ *
+ * <p>This lock supports a maximum of 65535 recursive write locks
+ * and 65535 read locks. Attempts to exceed these limits result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantReadWriteLock
+        implements ReadWriteLock, java.io.Serializable {
+    private static final long serialVersionUID = -6992448646407690164L;
+    /** Inner class providing readlock */
+    private final ReentrantReadWriteLock.ReadLock readerLock;
+    /** Inner class providing writelock */
+    private final ReentrantReadWriteLock.WriteLock writerLock;
+    /** Performs all synchronization mechanics */
+    final Sync sync;
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * default (nonfair) ordering properties.
+     */
+    public ReentrantReadWriteLock() {
+        this(false);
+    }
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * the given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantReadWriteLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+        readerLock = new ReadLock(this);
+        writerLock = new WriteLock(this);
+    }
+
+    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
+    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
+
+    /**
+     * Synchronization implementation for ReentrantReadWriteLock.
+     * Subclassed into fair and nonfair versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 6317671515068378041L;
+
+        /*
+         * Read vs write count extraction constants and functions.
+         * Lock state is logically divided into two unsigned shorts:
+         * The lower one representing the exclusive (writer) lock hold count,
+         * and the upper the shared (reader) hold count.
+         */
+
+        static final int SHARED_SHIFT   = 16;
+        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
+        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
+        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
+
+        /** Returns the number of shared holds represented in count. */
+        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
+        /** Returns the number of exclusive holds represented in count. */
+        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
+
+        /**
+         * A counter for per-thread read hold counts.
+         * Maintained as a ThreadLocal; cached in cachedHoldCounter.
+         */
+        static final class HoldCounter {
+            int count;          // initially 0
+            // Use id, not reference, to avoid garbage retention
+            final long tid = LockSupport.getThreadId(Thread.currentThread());
+        }
+
+        /**
+         * ThreadLocal subclass. Easiest to explicitly define for sake
+         * of deserialization mechanics.
+         */
+        static final class ThreadLocalHoldCounter
+            extends ThreadLocal<HoldCounter> {
+            public HoldCounter initialValue() {
+                return new HoldCounter();
+            }
+        }
+
+        /**
+         * The number of reentrant read locks held by current thread.
+         * Initialized only in constructor and readObject.
+         * Removed whenever a thread's read hold count drops to 0.
+         */
+        private transient ThreadLocalHoldCounter readHolds;
+
+        /**
+         * The hold count of the last thread to successfully acquire
+         * readLock. This saves ThreadLocal lookup in the common case
+         * where the next thread to release is the last one to
+         * acquire. This is non-volatile since it is just used
+         * as a heuristic, and would be great for threads to cache.
+         *
+         * <p>Can outlive the Thread for which it is caching the read
+         * hold count, but avoids garbage retention by not retaining a
+         * reference to the Thread.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's final field and out-of-thin-air guarantees.
+         */
+        private transient HoldCounter cachedHoldCounter;
+
+        /**
+         * firstReader is the first thread to have acquired the read lock.
+         * firstReaderHoldCount is firstReader's hold count.
+         *
+         * <p>More precisely, firstReader is the unique thread that last
+         * changed the shared count from 0 to 1, and has not released the
+         * read lock since then; null if there is no such thread.
+         *
+         * <p>Cannot cause garbage retention unless the thread terminated
+         * without relinquishing its read locks, since tryReleaseShared
+         * sets it to null.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's out-of-thin-air guarantees for references.
+         *
+         * <p>This allows tracking of read holds for uncontended read
+         * locks to be very cheap.
+         */
+        private transient Thread firstReader;
+        private transient int firstReaderHoldCount;
+
+        Sync() {
+            readHolds = new ThreadLocalHoldCounter();
+            setState(getState()); // ensures visibility of readHolds
+        }
+
+        /*
+         * Acquires and releases use the same code for fair and
+         * nonfair locks, but differ in whether/how they allow barging
+         * when queues are non-empty.
+         */
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the read lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean readerShouldBlock();
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the write lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean writerShouldBlock();
+
+        /*
+         * Note that tryRelease and tryAcquire can be called by
+         * Conditions. So it is possible that their arguments contain
+         * both read and write holds that are all released during a
+         * condition wait and re-established in tryAcquire.
+         */
+        @ReservedStackAccess
+        protected final boolean tryRelease(int releases) {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int nextc = getState() - releases;
+            boolean free = exclusiveCount(nextc) == 0;
+            if (free)
+                setExclusiveOwnerThread(null);
+            setState(nextc);
+            return free;
+        }
+
+        @ReservedStackAccess
+        protected final boolean tryAcquire(int acquires) {
+            /*
+             * Walkthrough:
+             * 1. If read count nonzero or write count nonzero
+             *    and owner is a different thread, fail.
+             * 2. If count would saturate, fail. (This can only
+             *    happen if count is already nonzero.)
+             * 3. Otherwise, this thread is eligible for lock if
+             *    it is either a reentrant acquire or
+             *    queue policy allows it. If so, update state
+             *    and set owner.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            int w = exclusiveCount(c);
+            if (c != 0) {
+                // (Note: if c != 0 and w == 0 then shared count != 0)
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w + exclusiveCount(acquires) > MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                // Reentrant acquire
+                setState(c + acquires);
+                return true;
+            }
+            if (writerShouldBlock() ||
+                !compareAndSetState(c, c + acquires))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        @ReservedStackAccess
+        protected final boolean tryReleaseShared(int unused) {
+            Thread current = Thread.currentThread();
+            if (firstReader == current) {
+                // assert firstReaderHoldCount > 0;
+                if (firstReaderHoldCount == 1)
+                    firstReader = null;
+                else
+                    firstReaderHoldCount--;
+            } else {
+                HoldCounter rh = cachedHoldCounter;
+                if (rh == null ||
+                    rh.tid != LockSupport.getThreadId(current))
+                    rh = readHolds.get();
+                int count = rh.count;
+                if (count <= 1) {
+                    readHolds.remove();
+                    if (count <= 0)
+                        throw unmatchedUnlockException();
+                }
+                --rh.count;
+            }
+            for (;;) {
+                int c = getState();
+                int nextc = c - SHARED_UNIT;
+                if (compareAndSetState(c, nextc))
+                    // Releasing the read lock has no effect on readers,
+                    // but it may allow waiting writers to proceed if
+                    // both read and write locks are now free.
+                    return nextc == 0;
+            }
+        }
+
+        private static IllegalMonitorStateException unmatchedUnlockException() {
+            return new IllegalMonitorStateException(
+                "attempt to unlock read lock, not locked by current thread");
+        }
+
+        @ReservedStackAccess
+        protected final int tryAcquireShared(int unused) {
+            /*
+             * Walkthrough:
+             * 1. If write lock held by another thread, fail.
+             * 2. Otherwise, this thread is eligible for
+             *    lock wrt state, so ask if it should block
+             *    because of queue policy. If not, try
+             *    to grant by CASing state and updating count.
+             *    Note that step does not check for reentrant
+             *    acquires, which is postponed to full version
+             *    to avoid having to check hold count in
+             *    the more typical non-reentrant case.
+             * 3. If step 2 fails either because thread
+             *    apparently not eligible or CAS fails or count
+             *    saturated, chain to version with full retry loop.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (exclusiveCount(c) != 0 &&
+                getExclusiveOwnerThread() != current)
+                return -1;
+            int r = sharedCount(c);
+            if (!readerShouldBlock() &&
+                r < MAX_COUNT &&
+                compareAndSetState(c, c + SHARED_UNIT)) {
+                if (r == 0) {
+                    firstReader = current;
+                    firstReaderHoldCount = 1;
+                } else if (firstReader == current) {
+                    firstReaderHoldCount++;
+                } else {
+                    HoldCounter rh = cachedHoldCounter;
+                    if (rh == null ||
+                        rh.tid != LockSupport.getThreadId(current))
+                        cachedHoldCounter = rh = readHolds.get();
+                    else if (rh.count == 0)
+                        readHolds.set(rh);
+                    rh.count++;
+                }
+                return 1;
+            }
+            return fullTryAcquireShared(current);
+        }
+
+        /**
+         * Full version of acquire for reads, that handles CAS misses
+         * and reentrant reads not dealt with in tryAcquireShared.
+         */
+        final int fullTryAcquireShared(Thread current) {
+            /*
+             * This code is in part redundant with that in
+             * tryAcquireShared but is simpler overall by not
+             * complicating tryAcquireShared with interactions between
+             * retries and lazily reading hold counts.
+             */
+            HoldCounter rh = null;
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0) {
+                    if (getExclusiveOwnerThread() != current)
+                        return -1;
+                    // else we hold the exclusive lock; blocking here
+                    // would cause deadlock.
+                } else if (readerShouldBlock()) {
+                    // Make sure we're not acquiring read lock reentrantly
+                    if (firstReader == current) {
+                        // assert firstReaderHoldCount > 0;
+                    } else {
+                        if (rh == null) {
+                            rh = cachedHoldCounter;
+                            if (rh == null ||
+                                rh.tid != LockSupport.getThreadId(current)) {
+                                rh = readHolds.get();
+                                if (rh.count == 0)
+                                    readHolds.remove();
+                            }
+                        }
+                        if (rh.count == 0)
+                            return -1;
+                    }
+                }
+                if (sharedCount(c) == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (sharedCount(c) == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        if (rh == null)
+                            rh = cachedHoldCounter;
+                        if (rh == null ||
+                            rh.tid != LockSupport.getThreadId(current))
+                            rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                        cachedHoldCounter = rh; // cache for release
+                    }
+                    return 1;
+                }
+            }
+        }
+
+        /**
+         * Performs tryLock for write, enabling barging in both modes.
+         * This is identical in effect to tryAcquire except for lack
+         * of calls to writerShouldBlock.
+         */
+        @ReservedStackAccess
+        final boolean tryWriteLock() {
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (c != 0) {
+                int w = exclusiveCount(c);
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+            }
+            if (!compareAndSetState(c, c + 1))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        /**
+         * Performs tryLock for read, enabling barging in both modes.
+         * This is identical in effect to tryAcquireShared except for
+         * lack of calls to readerShouldBlock.
+         */
+        @ReservedStackAccess
+        final boolean tryReadLock() {
+            Thread current = Thread.currentThread();
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0 &&
+                    getExclusiveOwnerThread() != current)
+                    return false;
+                int r = sharedCount(c);
+                if (r == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (r == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        HoldCounter rh = cachedHoldCounter;
+                        if (rh == null ||
+                            rh.tid != LockSupport.getThreadId(current))
+                            cachedHoldCounter = rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                    }
+                    return true;
+                }
+            }
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        // Methods relayed to outer class
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        final Thread getOwner() {
+            // Must read state before owner to ensure memory consistency
+            return ((exclusiveCount(getState()) == 0) ?
+                    null :
+                    getExclusiveOwnerThread());
+        }
+
+        final int getReadLockCount() {
+            return sharedCount(getState());
+        }
+
+        final boolean isWriteLocked() {
+            return exclusiveCount(getState()) != 0;
+        }
+
+        final int getWriteHoldCount() {
+            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
+        }
+
+        final int getReadHoldCount() {
+            if (getReadLockCount() == 0)
+                return 0;
+
+            Thread current = Thread.currentThread();
+            if (firstReader == current)
+                return firstReaderHoldCount;
+
+            HoldCounter rh = cachedHoldCounter;
+            if (rh != null && rh.tid == LockSupport.getThreadId(current))
+                return rh.count;
+
+            int count = readHolds.get().count;
+            if (count == 0) readHolds.remove();
+            return count;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            readHolds = new ThreadLocalHoldCounter();
+            setState(0); // reset to unlocked state
+        }
+
+        final int getCount() { return getState(); }
+    }
+
+    /**
+     * Nonfair version of Sync
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -8159625535654395037L;
+        final boolean writerShouldBlock() {
+            return false; // writers can always barge
+        }
+        final boolean readerShouldBlock() {
+            /* As a heuristic to avoid indefinite writer starvation,
+             * block if the thread that momentarily appears to be head
+             * of queue, if one exists, is a waiting writer.  This is
+             * only a probabilistic effect since a new reader will not
+             * block if there is a waiting writer behind other enabled
+             * readers that have not yet drained from the queue.
+             */
+            return apparentlyFirstQueuedIsExclusive();
+        }
+    }
+
+    /**
+     * Fair version of Sync
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -2274990926593161451L;
+        final boolean writerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+        final boolean readerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
+     */
+    public static class ReadLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -5992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected ReadLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the read lock.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then
+         * the current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until the read lock has been acquired.
+         */
+        public void lock() {
+            sync.acquireShared(1);
+        }
+
+        /**
+         * Acquires the read lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held
+         * by another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then the
+         * current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireSharedInterruptibly(1);
+        }
+
+        /**
+         * Acquires the read lock only if the write lock is not held by
+         * another thread at the time of invocation.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. Even when this lock has been set to use a
+         * fair ordering policy, a call to {@code tryLock()}
+         * <em>will</em> immediately acquire the read lock if it is
+         * available, whether or not other threads are currently
+         * waiting for the read lock.  This &quot;barging&quot; behavior
+         * can be useful in certain circumstances, even though it
+         * breaks fairness. If you want to honor the fairness setting
+         * for this lock, then use {@link #tryLock(long, TimeUnit)
+         * tryLock(0, TimeUnit.SECONDS)} which is almost equivalent
+         * (it also detects interruption).
+         *
+         * <p>If the write lock is held by another thread then
+         * this method will return immediately with the value
+         * {@code false}.
+         *
+         * @return {@code true} if the read lock was acquired
+         */
+        public boolean tryLock() {
+            return sync.tryReadLock();
+        }
+
+        /**
+         * Acquires the read lock if the write lock is not held by
+         * another thread within the given waiting time and the
+         * current thread has not been {@linkplain Thread#interrupt
+         * interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. If this lock has been set to use a fair
+         * ordering policy then an available lock <em>will not</em> be
+         * acquired if any other threads are waiting for the
+         * lock. This is in contrast to the {@link #tryLock()}
+         * 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> {@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
+         * purposes and lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses.
+         *
+         * </ul>
+         *
+         * <p>If the read lock is acquired then the value {@code true} is
+         * returned.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul> then {@link InterruptedException} is thrown and the
+         * current thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the read lock
+         * @param unit the time unit of the timeout argument
+         * @return {@code true} if the read lock was acquired
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the number of readers is now zero then the lock
+         * is made available for write lock attempts. If the current
+         * thread does not hold this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread
+         * does not hold this lock
+         */
+        public void unlock() {
+            sync.releaseShared(1);
+        }
+
+        /**
+         * Throws {@code UnsupportedOperationException} because
+         * {@code ReadLocks} do not support conditions.
+         *
+         * @throws UnsupportedOperationException always
+         */
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock state.
+         * The state, in brackets, includes the String {@code "Read locks ="}
+         * followed by the number of held read locks.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            int r = sync.getReadLockCount();
+            return super.toString() +
+                "[Read locks = " + r + "]";
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
+     */
+    public static class WriteLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -4992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected WriteLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the write lock.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds the write lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until the write lock has been acquired, at which
+         * time the write lock hold count is set to one.
+         */
+        public void lock() {
+            sync.acquire(1);
+        }
+
+        /**
+         * Acquires the write lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired by the current thread then the
+         * lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireInterruptibly(1);
+        }
+
+        /**
+         * Acquires the write lock only if it is not held by another thread
+         * at the time of invocation.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. Even when this lock has
+         * been set to use a fair ordering policy, a call to
+         * {@code tryLock()} <em>will</em> immediately acquire the
+         * lock if it is available, whether or not other threads are
+         * currently waiting for the write lock.  This &quot;barging&quot;
+         * behavior can be useful in certain circumstances, even
+         * though it breaks fairness. If you want to honor the
+         * fairness setting for this lock, then use {@link
+         * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS)}
+         * which is almost equivalent (it also detects interruption).
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then this method
+         * will return immediately with the value {@code false}.
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held
+         * by the current thread; and {@code false} otherwise.
+         */
+        public boolean tryLock() {
+            return sync.tryWriteLock();
+        }
+
+        /**
+         * Acquires the write lock if it is not held by another thread
+         * within the given waiting time and the current thread has
+         * not been {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. If this lock has been
+         * set to use a fair ordering policy then an available lock
+         * <em>will not</em> be acquired if any other threads are
+         * waiting for the write lock. This is in contrast to the {@link
+         * #tryLock()} 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> {@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
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired then the value {@code true} is
+         * returned and the write lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the write lock
+         * @param unit the time unit of the timeout argument
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held by the
+         * current thread; and {@code false} if the waiting time
+         * elapsed before the lock could be acquired.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the current thread is the holder of this lock then
+         * the hold count is decremented. If the hold count is now
+         * zero then the lock is released.  If the current thread is
+         * not the holder of this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread does not
+         * hold this lock
+         */
+        public void unlock() {
+            sync.release(1);
+        }
+
+        /**
+         * Returns a {@link Condition} instance for use with this
+         * {@link Lock} instance.
+         * <p>The returned {@link Condition} instance supports the same
+         * usages as do the {@link Object} monitor methods ({@link
+         * Object#wait() wait}, {@link Object#notify notify}, and {@link
+         * Object#notifyAll notifyAll}) when used with the built-in
+         * monitor lock.
+         *
+         * <ul>
+         *
+         * <li>If this write lock is not held when any {@link
+         * Condition} method is called then an {@link
+         * IllegalMonitorStateException} is thrown.  (Read locks are
+         * held independently of write locks, so are not checked or
+         * affected. However it is essentially always an error to
+         * invoke a condition waiting method when the current thread
+         * has also acquired read locks, since other threads that
+         * could unblock it will not be able to acquire the write
+         * lock.)
+         *
+         * <li>When the condition {@linkplain Condition#await() waiting}
+         * methods are called the write lock is released and, before
+         * they return, the write lock is reacquired and the lock hold
+         * count restored to what it was when the method was called.
+         *
+         * <li>If a thread is {@linkplain Thread#interrupt interrupted} while
+         * waiting then the wait will terminate, an {@link
+         * InterruptedException} will be thrown, and the thread's
+         * interrupted status will be cleared.
+         *
+         * <li>Waiting threads are signalled in FIFO order.
+         *
+         * <li>The ordering of lock reacquisition for threads returning
+         * from waiting methods is the same as for threads initially
+         * acquiring the lock, which is in the default case not specified,
+         * but for <em>fair</em> locks favors those threads that have been
+         * waiting the longest.
+         *
+         * </ul>
+         *
+         * @return the Condition object
+         */
+        public Condition newCondition() {
+            return sync.newCondition();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock
+         * state.  The state, in brackets includes either the String
+         * {@code "Unlocked"} or the String {@code "Locked by"}
+         * followed by the {@linkplain Thread#getName name} of the owning thread.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            Thread o = sync.getOwner();
+            return super.toString() + ((o == null) ?
+                                       "[Unlocked]" :
+                                       "[Locked by thread " + o.getName() + "]");
+        }
+
+        /**
+         * Queries if this write lock is held by the current thread.
+         * Identical in effect to {@link
+         * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
+         *
+         * @return {@code true} if the current thread holds this lock and
+         *         {@code false} otherwise
+         * @since 1.6
+         */
+        public boolean isHeldByCurrentThread() {
+            return sync.isHeldExclusively();
+        }
+
+        /**
+         * Queries the number of holds on this write lock by the current
+         * thread.  A thread has a hold on a lock for each lock action
+         * that is not matched by an unlock action.  Identical in effect
+         * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
+         *
+         * @return the number of holds on this lock by the current thread,
+         *         or zero if this lock is not held by the current thread
+         * @since 1.6
+         */
+        public int getHoldCount() {
+            return sync.getWriteHoldCount();
+        }
+    }
+
+    // Instrumentation and status
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns the write lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return sync.getReadLockCount();
+    }
+
+    /**
+     * Queries if the write lock is held by any thread. This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return {@code true} if any thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLocked() {
+        return sync.isWriteLocked();
+    }
+
+    /**
+     * Queries if the write lock is held by the current thread.
+     *
+     * @return {@code true} if the current thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLockedByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries the number of reentrant write holds on this lock by the
+     * current thread.  A writer thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the write lock by the current thread,
+     *         or zero if the write lock is not held by the current thread
+     */
+    public int getWriteHoldCount() {
+        return sync.getWriteHoldCount();
+    }
+
+    /**
+     * Queries the number of reentrant read holds on this lock by the
+     * current thread.  A reader thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the read lock by the current thread,
+     *         or zero if the read lock is not held by the current thread
+     * @since 1.6
+     */
+    public int getReadHoldCount() {
+        return sync.getReadHoldCount();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the write lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedWriterThreads() {
+        return sync.getExclusiveQueuedThreads();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the read lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedReaderThreads() {
+        return sync.getSharedQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire the read or
+     * write lock. Note that because cancellations may occur at any
+     * time, a {@code true} return does not guarantee that any other
+     * thread will ever acquire a lock.  This method is designed
+     * primarily for use in monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire either
+     * the read or write lock. Note that because cancellations may
+     * occur at any time, a {@code true} return does not guarantee
+     * that this thread will ever acquire a lock.  This method is
+     * designed primarily for use in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * either the read or write lock.  The value is only an estimate
+     * because the number of threads may change dynamically while this
+     * method traverses internal data structures.  This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire either the read or write lock.  Because the actual set
+     * of threads may change dynamically while constructing this
+     * result, the returned collection is only a best-effort estimate.
+     * The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with the write lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with the write lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with the write lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes the String {@code "Write locks ="}
+     * followed by the number of reentrantly held write locks, and the
+     * String {@code "Read locks ="} followed by the number of held
+     * read locks.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        int c = sync.getCount();
+        int w = Sync.exclusiveCount(c);
+        int r = Sync.sharedCount(c);
+
+        return super.toString() +
+            "[Write locks = " + w + ", Read locks = " + r + "]";
+    }
+
+}
diff --git a/android-35/java/util/concurrent/locks/StampedLock.java b/android-35/java/util/concurrent/locks/StampedLock.java
new file mode 100644
index 0000000..b9f0e93
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/StampedLock.java
@@ -0,0 +1,1498 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
+import jdk.internal.vm.annotation.ReservedStackAccess;
+
+/**
+ * A capability-based lock with three modes for controlling read/write
+ * access.  The state of a StampedLock consists of a version and mode.
+ * Lock acquisition methods return a stamp that represents and
+ * controls access with respect to a lock state; "try" versions of
+ * these methods may instead return the special value zero to
+ * represent failure to acquire access. Lock release and conversion
+ * methods require stamps as arguments, and fail if they do not match
+ * the state of the lock. The three modes are:
+ *
+ * <ul>
+ *
+ *  <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
+ *   waiting for exclusive access, returning a stamp that can be used
+ *   in method {@link #unlockWrite} to release the lock. Untimed and
+ *   timed versions of {@code tryWriteLock} are also provided. When
+ *   the lock is held in write mode, no read locks may be obtained,
+ *   and all optimistic read validations will fail.
+ *
+ *  <li><b>Reading.</b> Method {@link #readLock} possibly blocks
+ *   waiting for non-exclusive access, returning a stamp that can be
+ *   used in method {@link #unlockRead} to release the lock. Untimed
+ *   and timed versions of {@code tryReadLock} are also provided.
+ *
+ *  <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
+ *   returns a non-zero stamp only if the lock is not currently held in
+ *   write mode.  Method {@link #validate} returns true if the lock has not
+ *   been acquired in write mode since obtaining a given stamp, in which
+ *   case all actions prior to the most recent write lock release
+ *   happen-before actions following the call to {@code tryOptimisticRead}.
+ *   This mode can be thought of as an extremely weak version of a
+ *   read-lock, that can be broken by a writer at any time.  The use of
+ *   optimistic read mode for short read-only code segments often reduces
+ *   contention and improves throughput.  However, its use is inherently
+ *   fragile.  Optimistic read sections should only read fields and hold
+ *   them in local variables for later use after validation. Fields read
+ *   while in optimistic read mode may be wildly inconsistent, so usage
+ *   applies only when you are familiar enough with data representations to
+ *   check consistency and/or repeatedly invoke method {@code validate()}.
+ *   For example, such steps are typically required when first reading an
+ *   object or array reference, and then accessing one of its fields,
+ *   elements or methods.
+ *
+ * </ul>
+ *
+ * <p>This class also supports methods that conditionally provide
+ * conversions across the three modes. For example, method {@link
+ * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
+ * a valid write stamp if (1) already in writing mode (2) in reading
+ * mode and there are no other readers or (3) in optimistic read mode
+ * and the lock is available. The forms of these methods are designed to
+ * help reduce some of the code bloat that otherwise occurs in
+ * retry-based designs.
+ *
+ * <p>StampedLocks are designed for use as internal utilities in the
+ * development of thread-safe components. Their use relies on
+ * knowledge of the internal properties of the data, objects, and
+ * methods they are protecting.  They are not reentrant, so locked
+ * bodies should not call other unknown methods that may try to
+ * re-acquire locks (although you may pass a stamp to other methods
+ * that can use or convert it).  The use of read lock modes relies on
+ * the associated code sections being side-effect-free.  Unvalidated
+ * optimistic read sections cannot call methods that are not known to
+ * tolerate potential inconsistencies.  Stamps use finite
+ * representations, and are not cryptographically secure (i.e., a
+ * valid stamp may be guessable). Stamp values may recycle after (no
+ * sooner than) one year of continuous operation. A stamp held without
+ * use or validation for longer than this period may fail to validate
+ * correctly.  StampedLocks are serializable, but always deserialize
+ * into initial unlocked state, so they are not useful for remote
+ * locking.
+ *
+ * <p>Like {@link java.util.concurrent.Semaphore Semaphore}, but unlike most
+ * {@link Lock} implementations, StampedLocks have no notion of ownership.
+ * Locks acquired in one thread can be released or converted in another.
+ *
+ * <p>The scheduling policy of StampedLock does not consistently
+ * prefer readers over writers or vice versa.  All "try" methods are
+ * best-effort and do not necessarily conform to any scheduling or
+ * fairness policy. A zero return from any "try" method for acquiring
+ * or converting locks does not carry any information about the state
+ * of the lock; a subsequent invocation may succeed.
+ *
+ * <p>Because it supports coordinated usage across multiple lock
+ * modes, this class does not directly implement the {@link Lock} or
+ * {@link ReadWriteLock} interfaces. However, a StampedLock may be
+ * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link
+ * #asReadWriteLock()} in applications requiring only the associated
+ * set of functionality.
+ *
+ * <p><b>Memory Synchronization.</b> Methods with the effect of
+ * successfully locking in any mode have the same memory
+ * synchronization effects as a <em>Lock</em> action, as described in
+ * Chapter 17 of <cite>The Java Language Specification</cite>.
+ * Methods successfully unlocking in write mode have the same memory
+ * synchronization effects as an <em>Unlock</em> action.  In optimistic
+ * read usages, actions prior to the most recent write mode unlock action
+ * are guaranteed to happen-before those following a tryOptimisticRead
+ * only if a later validate returns true; otherwise there is no guarantee
+ * that the reads between tryOptimisticRead and validate obtain a
+ * consistent snapshot.
+ *
+ * <p><b>Sample Usage.</b> The following illustrates some usage idioms
+ * in a class that maintains simple two-dimensional points. The sample
+ * code illustrates some try/catch conventions even though they are
+ * not strictly needed here because no exceptions can occur in their
+ * bodies.
+ *
+ * <pre> {@code
+ * class Point {
+ *   private double x, y;
+ *   private final StampedLock sl = new StampedLock();
+ *
+ *   // an exclusively locked method
+ *   void move(double deltaX, double deltaY) {
+ *     long stamp = sl.writeLock();
+ *     try {
+ *       x += deltaX;
+ *       y += deltaY;
+ *     } finally {
+ *       sl.unlockWrite(stamp);
+ *     }
+ *   }
+ *
+ *   // a read-only method
+ *   // upgrade from optimistic read to read lock
+ *   double distanceFromOrigin() {
+ *     long stamp = sl.tryOptimisticRead();
+ *     try {
+ *       retryHoldingLock: for (;; stamp = sl.readLock()) {
+ *         if (stamp == 0L)
+ *           continue retryHoldingLock;
+ *         // possibly racy reads
+ *         double currentX = x;
+ *         double currentY = y;
+ *         if (!sl.validate(stamp))
+ *           continue retryHoldingLock;
+ *         return Math.hypot(currentX, currentY);
+ *       }
+ *     } finally {
+ *       if (StampedLock.isReadLockStamp(stamp))
+ *         sl.unlockRead(stamp);
+ *     }
+ *   }
+ *
+ *   // upgrade from optimistic read to write lock
+ *   void moveIfAtOrigin(double newX, double newY) {
+ *     long stamp = sl.tryOptimisticRead();
+ *     try {
+ *       retryHoldingLock: for (;; stamp = sl.writeLock()) {
+ *         if (stamp == 0L)
+ *           continue retryHoldingLock;
+ *         // possibly racy reads
+ *         double currentX = x;
+ *         double currentY = y;
+ *         if (!sl.validate(stamp))
+ *           continue retryHoldingLock;
+ *         if (currentX != 0.0 || currentY != 0.0)
+ *           break;
+ *         stamp = sl.tryConvertToWriteLock(stamp);
+ *         if (stamp == 0L)
+ *           continue retryHoldingLock;
+ *         // exclusive access
+ *         x = newX;
+ *         y = newY;
+ *         return;
+ *       }
+ *     } finally {
+ *       if (StampedLock.isWriteLockStamp(stamp))
+ *         sl.unlockWrite(stamp);
+ *     }
+ *   }
+ *
+ *   // upgrade read lock to write lock
+ *   void moveIfAtOrigin2(double newX, double newY) {
+ *     long stamp = sl.readLock();
+ *     try {
+ *       while (x == 0.0 && y == 0.0) {
+ *         long ws = sl.tryConvertToWriteLock(stamp);
+ *         if (ws != 0L) {
+ *           stamp = ws;
+ *           x = newX;
+ *           y = newY;
+ *           break;
+ *         }
+ *         else {
+ *           sl.unlockRead(stamp);
+ *           stamp = sl.writeLock();
+ *         }
+ *       }
+ *     } finally {
+ *       sl.unlock(stamp);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @jls 17.4 Memory Model
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class StampedLock implements java.io.Serializable {
+    /*
+     * Algorithmic notes:
+     *
+     * The design employs elements of Sequence locks
+     * (as used in linux kernels; see Lameter's
+     * http://www.lameter.com/gelato2005.pdf
+     * and elsewhere; see
+     * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
+     * and Ordered RW locks (see Shirako et al
+     * http://dl.acm.org/citation.cfm?id=2312015)
+     *
+     * Conceptually, the primary state of the lock includes a sequence
+     * number that is odd when write-locked and even otherwise.
+     * However, this is offset by a reader count that is non-zero when
+     * read-locked.  The read count is ignored when validating
+     * "optimistic" seqlock-reader-style stamps.  Because we must use
+     * a small finite number of bits (currently 7) for readers, a
+     * supplementary reader overflow word is used when the number of
+     * readers exceeds the count field. We do this by treating the max
+     * reader count value (RBITS) as a spinlock protecting overflow
+     * updates.
+     *
+     * Waiters use a modified form of CLH lock used in
+     * AbstractQueuedSynchronizer (AQS; see its internal documentation
+     * for a fuller account), where each node is either a ReaderNode
+     * or WriterNode. Implementation of queued Writer mode is
+     * identical to AQS except for lock-state operations.  Sets of
+     * waiting readers are grouped (linked) under a common node (field
+     * cowaiters) so act as a single node with respect to most CLH
+     * mechanics.  This simplifies the scheduling policy to a
+     * mainly-FIFO scheme that incorporates elements of Phase-Fair
+     * locks (see Brandenburg & Anderson, especially
+     * http://www.cs.unc.edu/~bbb/diss/).  Method release does not
+     * itself wake up cowaiters. This is done by the primary thread,
+     * but helped by other cowaiters as they awaken.
+     *
+     * These rules apply to threads actually queued. Threads may also
+     * try to acquire locks before or in the process of enqueueing
+     * regardless of preference rules, and so may "barge" their way
+     * in.  Methods writeLock and readLock (but not the other variants
+     * of each) first unconditionally try to CAS state, falling back
+     * to test-and-test-and-set retries on failure, slightly shrinking
+     * race windows on initial attempts, thus making success more
+     * likely. Also, when some threads cancel (via interrupt or
+     * timeout), phase-fairness is at best roughly approximated.
+     *
+     * Nearly all of these mechanics are carried out in methods
+     * acquireWrite and acquireRead, that, as typical of such code,
+     * sprawl out because actions and retries rely on consistent sets
+     * of locally cached reads.
+     *
+     * For an explanation of the use of acquireFence, see
+     * http://gee.cs.oswego.edu/dl/html/j9mm.html as well as Boehm's
+     * paper (above). Note that sequence validation (mainly method
+     * validate()) requires stricter ordering rules than apply to
+     * normal volatile reads (of "state").  To ensure that writeLock
+     * acquisitions strictly precede subsequent writes in cases where
+     * this is not already forced, we use a storeStoreFence.
+     *
+     * The memory layout keeps lock state and queue pointers together
+     * (normally on the same cache line). This usually works well for
+     * read-mostly loads. In most other cases, the natural tendency of
+     * CLH locks to reduce memory contention lessens motivation to
+     * further spread out contended locations, but might be subject to
+     * future improvements.
+     */
+
+    private static final long serialVersionUID = -6001602636862214147L;
+
+    /** The number of bits to use for reader count before overflowing */
+    private static final int LG_READERS = 7; // 127 readers
+
+    // Values for lock state and stamp operations
+    private static final long RUNIT = 1L;
+    private static final long WBIT  = 1L << LG_READERS;
+    private static final long RBITS = WBIT - 1L;
+    private static final long RFULL = RBITS - 1L;
+    private static final long ABITS = RBITS | WBIT;
+    private static final long SBITS = ~RBITS; // note overlap with ABITS
+    // not writing and conservatively non-overflowing
+    private static final long RSAFE = ~(3L << (LG_READERS - 1));
+
+    /*
+     * 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
+     * write mode: m == WBIT
+     * optimistic read mode: m == 0L (even when read lock is held)
+     * read mode: m > 0L && m <= RFULL (the stamp is a copy of state, but the
+     * read hold count in the stamp is unused other than to determine mode)
+     *
+     * This differs slightly from the encoding of state:
+     * (state & ABITS) == 0L indicates the lock is currently unlocked.
+     * (state & ABITS) == RBITS is a special transient value
+     * indicating spin-locked to manipulate reader bits overflow.
+     */
+
+    /** Initial value for lock state; avoids failure value zero. */
+    private static final long ORIGIN = WBIT << 1;
+
+    // Special value from cancelled acquire methods so caller can throw IE
+    private static final long INTERRUPTED = 1L;
+
+    // Bits for Node.status
+    static final int WAITING   = 1;
+    static final int CANCELLED = 0x80000000; // must be negative
+
+    /** CLH nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    static final class WriterNode extends Node { // node for writers
+    }
+
+    static final class ReaderNode extends Node { // node for readers
+        volatile ReaderNode cowaiters;           // list of linked readers
+        final boolean casCowaiters(ReaderNode c, ReaderNode v) {
+            return U.weakCompareAndSetReference(this, COWAITERS, c, v);
+        }
+        final void setCowaitersRelaxed(ReaderNode p) {
+            U.putReference(this, COWAITERS, p);
+        }
+        private static final long COWAITERS
+            = U.objectFieldOffset(ReaderNode.class, "cowaiters");
+    }
+
+    /** Head of CLH queue */
+    private transient volatile Node head;
+    /** Tail (last) of CLH queue */
+    private transient volatile Node tail;
+
+    // views
+    transient ReadLockView readLockView;
+    transient WriteLockView writeLockView;
+    transient ReadWriteLockView readWriteLockView;
+
+    /** Lock sequence/state */
+    private transient volatile long state;
+    /** extra reader count when state read count saturated */
+    private transient int readerOverflow;
+
+    /**
+     * Creates a new lock, initially in unlocked state.
+     */
+    public StampedLock() {
+        state = ORIGIN;
+    }
+
+    // internal lock methods
+
+    private boolean casState(long expect, long update) {
+        return U.compareAndSetLong(this, STATE, expect, update);
+    }
+
+    @ReservedStackAccess
+    private long tryAcquireWrite() {
+        long s, nextState;
+        if (((s = state) & ABITS) == 0L && casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return 0L;
+    }
+
+    @ReservedStackAccess
+    private long tryAcquireRead() {
+        for (long s, m, nextState;;) {
+            if ((m = (s = state) & ABITS) < RFULL) {
+                if (casState(s, nextState = s + RUNIT))
+                    return nextState;
+            }
+            else if (m == WBIT)
+                return 0L;
+            else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                return nextState;
+        }
+    }
+
+    /**
+     * Returns an unlocked state, incrementing the version and
+     * avoiding special failure value 0L.
+     *
+     * @param s a write-locked state (or stamp)
+     */
+    private static long unlockWriteState(long s) {
+        return ((s += WBIT) == 0L) ? ORIGIN : s;
+    }
+
+    private long releaseWrite(long s) {
+        long nextState = state = unlockWriteState(s);
+        signalNext(head);
+        return nextState;
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a write stamp that can be used to unlock or convert mode
+     */
+    @ReservedStackAccess
+    public long writeLock() {
+        // try unconditional CAS confirming weak read
+        long s = U.getLongOpaque(this, STATE) & ~ABITS, nextState;
+        if (casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return acquireWrite(false, false, 0L);
+    }
+
+    /**
+     * Exclusively acquires the lock if it is immediately available.
+     *
+     * @return a write stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryWriteLock() {
+        return tryAcquireWrite();
+    }
+
+    /**
+     * Exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a write stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryWriteLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            long nextState;
+            if ((nextState = tryAcquireWrite()) != 0L)
+                return nextState;
+            if (nanos <= 0L)
+                return 0L;
+            nextState = acquireWrite(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a write stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long writeLockInterruptibly() throws InterruptedException {
+        long nextState;
+        if (!Thread.interrupted() &&
+            ((nextState = tryAcquireWrite()) != 0L ||
+             (nextState = acquireWrite(true, false, 0L)) != INTERRUPTED))
+            return nextState;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a read stamp that can be used to unlock or convert mode
+     */
+    @ReservedStackAccess
+    public long readLock() {
+        // unconditionally optimistically try non-overflow case once
+        long s = U.getLongOpaque(this, STATE) & RSAFE, nextState;
+        if (casState(s, nextState = s + RUNIT))
+            return nextState;
+        else
+            return acquireRead(false, false, 0L);
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is immediately available.
+     *
+     * @return a read stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryReadLock() {
+        return tryAcquireRead();
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a read stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryReadLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            long nextState;
+            if (tail == head && (nextState = tryAcquireRead()) != 0L)
+                return nextState;
+            if (nanos <= 0L)
+                return 0L;
+            nextState = acquireRead(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a read stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long readLockInterruptibly() throws InterruptedException {
+        long nextState;
+        if (!Thread.interrupted() &&
+            ((nextState = tryAcquireRead()) != 0L ||
+             (nextState = acquireRead(true, false, 0L)) != INTERRUPTED))
+            return nextState;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Returns a stamp that can later be validated, or zero
+     * if exclusively locked.
+     *
+     * @return a valid optimistic read stamp, or zero if exclusively locked
+     */
+    public long tryOptimisticRead() {
+        long s;
+        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
+    }
+
+    /**
+     * Returns true if the lock has not been exclusively acquired
+     * since issuance of the given stamp. Always returns false if the
+     * stamp is zero. Always returns true if the stamp represents a
+     * currently held lock. Invoking this method with a value not
+     * obtained from {@link #tryOptimisticRead} or a locking method
+     * for this lock has no defined effect or result.
+     *
+     * @param stamp a stamp
+     * @return {@code true} if the lock has not been exclusively acquired
+     * since issuance of the given stamp; else false
+     */
+    public boolean validate(long stamp) {
+        U.loadFence();
+        return (stamp & SBITS) == (state & SBITS);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * exclusive lock.
+     *
+     * @param stamp a stamp returned by a write-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    @ReservedStackAccess
+    public void unlockWrite(long stamp) {
+        if (state != stamp || (stamp & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        releaseWrite(stamp);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * non-exclusive lock.
+     *
+     * @param stamp a stamp returned by a read-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    @ReservedStackAccess
+    public void unlockRead(long stamp) {
+        long s, m;
+        if ((stamp & RBITS) != 0L) {
+            while (((s = state) & SBITS) == (stamp & SBITS) &&
+                   ((m = s & RBITS) != 0L)) {
+                if (m < RFULL) {
+                    if (casState(s, s - RUNIT)) {
+                        if (m == RUNIT)
+                            signalNext(head);
+                        return;
+                    }
+                }
+                else if (tryDecReaderOverflow(s) != 0L)
+                    return;
+            }
+        }
+        throw new IllegalMonitorStateException();
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * corresponding mode of the lock.
+     *
+     * @param stamp a stamp returned by a lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlock(long stamp) {
+        if ((stamp & WBIT) != 0L)
+            unlockWrite(stamp);
+        else
+            unlockRead(stamp);
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, returns it.  Or, if a read lock, if the write lock is
+     * available, releases the read lock and returns a write stamp.
+     * Or, if an optimistic read, returns a write stamp only if
+     * immediately available. This method returns zero in all other
+     * cases.
+     *
+     * @param stamp a stamp
+     * @return a valid write stamp, or zero on failure
+     */
+    public long tryConvertToWriteLock(long stamp) {
+        long a = stamp & ABITS, m, s, nextState;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                if (casState(s, nextState = s | WBIT)) {
+                    U.storeStoreFence();
+                    return nextState;
+                }
+            } else if (m == WBIT) {
+                if (a != m)
+                    break;
+                return stamp;
+            } else if (m == RUNIT && a != 0L) {
+                if (casState(s, nextState = s - RUNIT + WBIT))
+                    return nextState;
+            } else
+                break;
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, releases it and obtains a read lock.  Or, if a read lock,
+     * returns it. Or, if an optimistic read, acquires a read lock and
+     * returns a read stamp only if immediately available. This method
+     * returns zero in all other cases.
+     *
+     * @param stamp a stamp
+     * @return a valid read stamp, or zero on failure
+     */
+    public long tryConvertToReadLock(long stamp) {
+        long a, s, nextState;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((a = stamp & ABITS) >= WBIT) {
+                if (s != stamp) // write stamp
+                    break;
+                nextState = state = unlockWriteState(s) + RUNIT;
+                signalNext(head);
+                return nextState;
+            } else if (a == 0L) { // optimistic read stamp
+                if ((s & ABITS) < RFULL) {
+                    if (casState(s, nextState = s + RUNIT))
+                        return nextState;
+                } else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                    return nextState;
+            } else { // already a read stamp
+                if ((s & ABITS) == 0L)
+                    break;
+                return stamp;
+            }
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp then, atomically, if the stamp
+     * represents holding a lock, releases it and returns an
+     * observation stamp.  Or, if an optimistic read, returns it if
+     * validated. This method returns zero in all other cases, and so
+     * may be useful as a form of "tryUnlock".
+     *
+     * @param stamp a stamp
+     * @return a valid optimistic read stamp, or zero on failure
+     */
+    public long tryConvertToOptimisticRead(long stamp) {
+        long a, m, s, nextState;
+        U.loadFence();
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((a = stamp & ABITS) >= WBIT) {
+                if (s != stamp)   // write stamp
+                    break;
+                return releaseWrite(s);
+            } else if (a == 0L) { // already an optimistic read stamp
+                return stamp;
+            } else if ((m = s & ABITS) == 0L) { // invalid read stamp
+                break;
+            } else if (m < RFULL) {
+                if (casState(s, nextState = s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return nextState & SBITS;
+                }
+            } else if ((nextState = tryDecReaderOverflow(s)) != 0L)
+                return nextState & SBITS;
+        }
+        return 0L;
+    }
+
+    /**
+     * Releases the write lock if it is held, without requiring a
+     * stamp value. This method may be useful for recovery after
+     * errors.
+     *
+     * @return {@code true} if the lock was held, else false
+     */
+    @ReservedStackAccess
+    public boolean tryUnlockWrite() {
+        long s;
+        if (((s = state) & WBIT) != 0L) {
+            releaseWrite(s);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Releases one hold of the read lock if it is held, without
+     * requiring a stamp value. This method may be useful for recovery
+     * after errors.
+     *
+     * @return {@code true} if the read lock was held, else false
+     */
+    @ReservedStackAccess
+    public boolean tryUnlockRead() {
+        long s, m;
+        while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
+            if (m < RFULL) {
+                if (casState(s, s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return true;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return true;
+        }
+        return false;
+    }
+
+    // status monitoring methods
+
+    /**
+     * Returns combined state-held and overflow read count for given
+     * state s.
+     */
+    private int getReadLockCount(long s) {
+        long readers;
+        if ((readers = s & RBITS) >= RFULL)
+            readers = RFULL + readerOverflow;
+        return (int) readers;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held exclusively.
+     *
+     * @return {@code true} if the lock is currently held exclusively
+     */
+    public boolean isWriteLocked() {
+        return (state & WBIT) != 0L;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held non-exclusively.
+     *
+     * @return {@code true} if the lock is currently held non-exclusively
+     */
+    public boolean isReadLocked() {
+        return (state & RBITS) != 0L;
+    }
+
+    /**
+     * Tells whether a stamp represents holding a lock exclusively.
+     * This method may be useful in conjunction with
+     * {@link #tryConvertToWriteLock}, for example: <pre> {@code
+     * long stamp = sl.tryOptimisticRead();
+     * try {
+     *   ...
+     *   stamp = sl.tryConvertToWriteLock(stamp);
+     *   ...
+     * } finally {
+     *   if (StampedLock.isWriteLockStamp(stamp))
+     *     sl.unlockWrite(stamp);
+     * }}</pre>
+     *
+     * @param stamp a stamp returned by a previous StampedLock operation
+     * @return {@code true} if the stamp was returned by a successful
+     *   write-lock operation
+     * @since 10
+     */
+    public static boolean isWriteLockStamp(long stamp) {
+        return (stamp & ABITS) == WBIT;
+    }
+
+    /**
+     * Tells whether a stamp represents holding a lock non-exclusively.
+     * This method may be useful in conjunction with
+     * {@link #tryConvertToReadLock}, for example: <pre> {@code
+     * long stamp = sl.tryOptimisticRead();
+     * try {
+     *   ...
+     *   stamp = sl.tryConvertToReadLock(stamp);
+     *   ...
+     * } finally {
+     *   if (StampedLock.isReadLockStamp(stamp))
+     *     sl.unlockRead(stamp);
+     * }}</pre>
+     *
+     * @param stamp a stamp returned by a previous StampedLock operation
+     * @return {@code true} if the stamp was returned by a successful
+     *   read-lock operation
+     * @since 10
+     */
+    public static boolean isReadLockStamp(long stamp) {
+        return (stamp & RBITS) != 0L;
+    }
+
+    /**
+     * Tells whether a stamp represents holding a lock.
+     * This method may be useful in conjunction with
+     * {@link #tryConvertToReadLock} and {@link #tryConvertToWriteLock},
+     * for example: <pre> {@code
+     * long stamp = sl.tryOptimisticRead();
+     * try {
+     *   ...
+     *   stamp = sl.tryConvertToReadLock(stamp);
+     *   ...
+     *   stamp = sl.tryConvertToWriteLock(stamp);
+     *   ...
+     * } finally {
+     *   if (StampedLock.isLockStamp(stamp))
+     *     sl.unlock(stamp);
+     * }}</pre>
+     *
+     * @param stamp a stamp returned by a previous StampedLock operation
+     * @return {@code true} if the stamp was returned by a successful
+     *   read-lock or write-lock operation
+     * @since 10
+     */
+    public static boolean isLockStamp(long stamp) {
+        return (stamp & ABITS) != 0L;
+    }
+
+    /**
+     * Tells whether a stamp represents a successful optimistic read.
+     *
+     * @param stamp a stamp returned by a previous StampedLock operation
+     * @return {@code true} if the stamp was returned by a successful
+     *   optimistic read operation, that is, a non-zero return from
+     *   {@link #tryOptimisticRead()} or
+     *   {@link #tryConvertToOptimisticRead(long)}
+     * @since 10
+     */
+    public static boolean isOptimisticReadStamp(long stamp) {
+        return (stamp & ABITS) == 0L && stamp != 0L;
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return getReadLockCount(state);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock
+     * state.  The state, in brackets, includes the String {@code
+     * "Unlocked"} or the String {@code "Write-locked"} or the String
+     * {@code "Read-locks:"} followed by the current number of
+     * read-locks held.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        long s = state;
+        return super.toString() +
+            ((s & ABITS) == 0L ? "[Unlocked]" :
+             (s & WBIT) != 0L ? "[Write-locked]" :
+             "[Read-locks:" + getReadLockCount(s) + "]");
+    }
+
+    // views
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #readLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link Lock#newCondition()}
+     * throws {@code UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asReadLock() {
+        ReadLockView v;
+        if ((v = readLockView) != null) return v;
+        return readLockView = new ReadLockView();
+    }
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #writeLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link Lock#newCondition()}
+     * throws {@code UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asWriteLock() {
+        WriteLockView v;
+        if ((v = writeLockView) != null) return v;
+        return writeLockView = new WriteLockView();
+    }
+
+    /**
+     * Returns a {@link ReadWriteLock} view of this StampedLock in
+     * which the {@link ReadWriteLock#readLock()} method is mapped to
+     * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to
+     * {@link #asWriteLock()}.
+     *
+     * @return the lock
+     */
+    public ReadWriteLock asReadWriteLock() {
+        ReadWriteLockView v;
+        if ((v = readWriteLockView) != null) return v;
+        return readWriteLockView = new ReadWriteLockView();
+    }
+
+    // view classes
+
+    final class ReadLockView implements Lock {
+        public void lock() { readLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            readLockInterruptibly();
+        }
+        public boolean tryLock() { return tryReadLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryReadLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockRead(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class WriteLockView implements Lock {
+        public void lock() { writeLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            writeLockInterruptibly();
+        }
+        public boolean tryLock() { return tryWriteLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryWriteLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockWrite(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class ReadWriteLockView implements ReadWriteLock {
+        public Lock readLock() { return asReadLock(); }
+        public Lock writeLock() { return asWriteLock(); }
+    }
+
+    // Unlock methods without stamp argument checks for view classes.
+    // Needed because view-class lock methods throw away stamps.
+
+    final void unstampedUnlockWrite() {
+        long s;
+        if (((s = state) & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        releaseWrite(s);
+    }
+
+    final void unstampedUnlockRead() {
+        long s, m;
+        while ((m = (s = state) & RBITS) > 0L) {
+            if (m < RFULL) {
+                if (casState(s, s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return;
+        }
+        throw new IllegalMonitorStateException();
+    }
+
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        state = ORIGIN; // reset to unlocked state
+    }
+
+    // overflow handling methods
+
+    /**
+     * Tries to increment readerOverflow by first setting state
+     * access bits value to RBITS, indicating hold of spinlock,
+     * then updating, then releasing.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryIncReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            ++readerOverflow;
+            return state = s;
+        }
+        return 0L;
+    }
+
+    /**
+     * Tries to decrement readerOverflow.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryDecReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            int r; long nextState;
+            if ((r = readerOverflow) > 0) {
+                readerOverflow = r - 1;
+                nextState = s;
+            }
+            else
+                nextState = s - RUNIT;
+            return state = nextState;
+        }
+        return 0L;
+    }
+
+    // release methods
+
+    /**
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    static final void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status > 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Removes and unparks all cowaiters of node, if it exists.
+     */
+    private static void signalCowaiters(ReaderNode node) {
+        if (node != null) {
+            for (ReaderNode c; (c = node.cowaiters) != null; ) {
+                if (node.casCowaiters(c, c.cowaiters))
+                    LockSupport.unpark(c.waiter);
+            }
+        }
+    }
+
+    // queue link methods
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new WriterNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * For explanation, see above and AbstractQueuedSynchronizer
+     * internal documentation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireWrite(boolean interruptible, boolean timed, long time) {
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        WriterNode node = null;
+        Node pred = null;
+        for (long s, nextState;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if ((first || pred == null) && ((s = state) & ABITS) == 0L &&
+                casState(s, nextState = s | WBIT)) {
+                U.storeStoreFence();
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+                return nextState;
+            } else if (node == null) {          // retry before enqueuing
+                node = new WriterNode();
+            } else if (pred == null) {          // try to enqueue
+                Node t = tail;
+                node.setPrevRelaxed(t);
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {   // reduce unfairness
+                --spins;
+                Thread.onSpinWait();
+            } else if (node.status == 0) {      // enable signal
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted);
+    }
+
+    /**
+     * See above for explanation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireRead(boolean interruptible, boolean timed, long time) {
+        boolean interrupted = false;
+        ReaderNode node = null;
+        /*
+         * Loop:
+         *   if empty, try to acquire
+         *   if tail is Reader, try to cowait; restart if leader stale or cancels
+         *   else try to create and enqueue node, and wait in 2nd loop below
+         */
+        for (;;) {
+            ReaderNode leader; long nextState;
+            Node tailPred = null, t = tail;
+            if ((t == null || (tailPred = t.prev) == null) &&
+                (nextState = tryAcquireRead()) != 0L) // try now if empty
+                return nextState;
+            else if (t == null)
+                tryInitializeHead();
+            else if (tailPred == null || !(t instanceof ReaderNode)) {
+                if (node == null)
+                    node = new ReaderNode();
+                if (tail == t) {
+                    node.setPrevRelaxed(t);
+                    if (casTail(t, node)) {
+                        t.next = node;
+                        break; // node is leader; wait in loop below
+                    }
+                    node.setPrevRelaxed(null);
+                }
+            } else if ((leader = (ReaderNode)t) == tail) { // try to cowait
+                for (boolean attached = false;;) {
+                    if (leader.status < 0 || leader.prev == null)
+                        break;
+                    else if (node == null)
+                        node = new ReaderNode();
+                    else if (node.waiter == null)
+                        node.waiter = Thread.currentThread();
+                    else if (!attached) {
+                        ReaderNode c = leader.cowaiters;
+                        node.setCowaitersRelaxed(c);
+                        attached = leader.casCowaiters(c, node);
+                        if (!attached)
+                            node.setCowaitersRelaxed(null);
+                    } else {
+                        long nanos = 0L;
+                        if (!timed)
+                            LockSupport.park(this);
+                        else if ((nanos = time - System.nanoTime()) > 0L)
+                            LockSupport.parkNanos(this, nanos);
+                        interrupted |= Thread.interrupted();
+                        if ((interrupted && interruptible) ||
+                            (timed && nanos <= 0L))
+                            return cancelCowaiter(node, leader, interrupted);
+                    }
+                }
+                if (node != null)
+                    node.waiter = null;
+                long ns = tryAcquireRead();
+                signalCowaiters(leader);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                if (ns != 0L)
+                    return ns;
+                else
+                    node = null; // restart if stale, missed, or leader cancelled
+            }
+        }
+
+        // node is leader of a cowait group; almost same as acquireWrite
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean first = false;
+        Node pred = null;
+        for (long nextState;;) {
+            if (!first && (pred = node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if ((first || pred == null) &&
+                (nextState = tryAcquireRead()) != 0L) {
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
+                }
+                signalCowaiters(node);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                return nextState;
+            } else if (first && spins != 0) {
+                --spins;
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted);
+    }
+
+    // Cancellation support
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p && q.status >= 0) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * If leader exists, possibly repeatedly traverses cowaiters,
+     * unsplicing the given cancelled node until not found.
+     */
+    private void unlinkCowaiter(ReaderNode node, ReaderNode leader) {
+        if (leader != null) {
+            while (leader.prev != null && leader.status >= 0) {
+                for (ReaderNode p = leader, q; ; p = q) {
+                    if ((q = p.cowaiters) == null)
+                        return;
+                    if (q == node) {
+                        p.casCowaiters(q, q.cowaiters);
+                        break;  // recheck even if succeeded
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * If node non-null, forces cancel status and unsplices it from
+     * queue, wakes up any cowaiters, and possibly wakes up successor
+     * to recheck status.
+     *
+     * @param node the waiter (may be null if not yet enqueued)
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelAcquire(Node node, boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            cleanQueue();
+            if (node instanceof ReaderNode)
+                signalCowaiters((ReaderNode)node);
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    /**
+     * If node non-null, forces cancel status and unsplices from
+     * leader's cowaiters list unless/until it is also cancelled.
+     *
+     * @param node if non-null, the waiter
+     * @param leader if non-null, the node heading cowaiters list
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelCowaiter(ReaderNode node, ReaderNode leader,
+                                boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            unlinkCowaiter(node, leader);
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(StampedLock.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(StampedLock.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(StampedLock.class, "tail");
+
+    static {
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/android-35/java/util/concurrent/locks/package-info.java b/android-35/java/util/concurrent/locks/package-info.java
new file mode 100644
index 0000000..97dfcc9
--- /dev/null
+++ b/android-35/java/util/concurrent/locks/package-info.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Interfaces and classes providing a framework for locking and waiting
+ * for conditions that is distinct from built-in synchronization and
+ * monitors.  The framework permits much greater flexibility in the use of
+ * locks and conditions, at the expense of more awkward syntax.
+ *
+ * <p>The {@link java.util.concurrent.locks.Lock} interface supports
+ * locking disciplines that differ in semantics (reentrant, fair, etc),
+ * and that can be used in non-block-structured contexts including
+ * hand-over-hand and lock reordering algorithms.  The main implementation
+ * is {@link java.util.concurrent.locks.ReentrantLock}.
+ *
+ * <p>The {@link java.util.concurrent.locks.ReadWriteLock} interface
+ * similarly defines locks that may be shared among readers but are
+ * exclusive to writers.  Only a single implementation, {@link
+ * java.util.concurrent.locks.ReentrantReadWriteLock}, is provided, since
+ * it covers most standard usage contexts.  But programmers may create
+ * their own implementations to cover nonstandard requirements.
+ *
+ * <p>The {@link java.util.concurrent.locks.Condition} interface
+ * describes condition variables that may be associated with Locks.
+ * These are similar in usage to the implicit monitors accessed using
+ * {@code Object.wait}, but offer extended capabilities.
+ * In particular, multiple {@code Condition} objects may be associated
+ * with a single {@code Lock}.  To avoid compatibility issues, the
+ * names of {@code Condition} methods are different from the
+ * corresponding {@code Object} versions.
+ *
+ * <p>The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer}
+ * class serves as a useful superclass for defining locks and other
+ * synchronizers that rely on queuing blocked threads.  The {@link
+ * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class
+ * provides the same functionality but extends support to 64 bits of
+ * synchronization state.  Both extend class {@link
+ * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple
+ * class that helps record the thread currently holding exclusive
+ * synchronization.  The {@link java.util.concurrent.locks.LockSupport}
+ * class provides lower-level blocking and unblocking support that is
+ * useful for those developers implementing their own customized lock
+ * classes.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.locks;
diff --git a/android-35/java/util/concurrent/package-info.java b/android-35/java/util/concurrent/package-info.java
new file mode 100644
index 0000000..dd0c8f7
--- /dev/null
+++ b/android-35/java/util/concurrent/package-info.java
@@ -0,0 +1,308 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Utility classes commonly useful in concurrent programming.  This
+ * package includes a few small standardized extensible frameworks, as
+ * well as some classes that provide useful functionality and are
+ * otherwise tedious or difficult to implement.  Here are brief
+ * descriptions of the main components.  See also the
+ * {@link java.util.concurrent.locks} and
+ * {@link java.util.concurrent.atomic} packages.
+ *
+ * <h2>Executors</h2>
+ *
+ * <b>Interfaces.</b>
+ *
+ * {@link java.util.concurrent.Executor} is a simple standardized
+ * interface for defining custom thread-like subsystems, including
+ * thread pools, asynchronous I/O, and lightweight task frameworks.
+ * Depending on which concrete Executor class is being used, tasks may
+ * execute in a newly created thread, an existing task-execution thread,
+ * or the thread calling {@link java.util.concurrent.Executor#execute
+ * execute}, and may execute sequentially or concurrently.
+ *
+ * {@link java.util.concurrent.ExecutorService} provides a more
+ * complete asynchronous task execution framework.  An
+ * ExecutorService manages queuing and scheduling of tasks,
+ * and allows controlled shutdown.
+ *
+ * The {@link java.util.concurrent.ScheduledExecutorService}
+ * subinterface and associated interfaces add support for
+ * delayed and periodic task execution.  ExecutorServices
+ * provide methods arranging asynchronous execution of any
+ * function expressed as {@link java.util.concurrent.Callable},
+ * the result-bearing analog of {@link java.lang.Runnable}.
+ *
+ * A {@link java.util.concurrent.Future} returns the results of
+ * a function, allows determination of whether execution has
+ * completed, and provides a means to cancel execution.
+ *
+ * A {@link java.util.concurrent.RunnableFuture} is a {@code Future}
+ * that possesses a {@code run} method that upon execution,
+ * sets its results.
+ *
+ * <p>
+ *
+ * <b>Implementations.</b>
+ *
+ * Classes {@link java.util.concurrent.ThreadPoolExecutor} and
+ * {@link java.util.concurrent.ScheduledThreadPoolExecutor}
+ * provide tunable, flexible thread pools.
+ *
+ * The {@link java.util.concurrent.Executors} class provides
+ * factory methods for the most common kinds and configurations
+ * of Executors, as well as a few utility methods for using
+ * them.  Other utilities based on {@code Executors} include the
+ * concrete class {@link java.util.concurrent.FutureTask}
+ * providing a common extensible implementation of Futures, and
+ * {@link java.util.concurrent.ExecutorCompletionService}, that
+ * assists in coordinating the processing of groups of
+ * asynchronous tasks.
+ *
+ * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an
+ * Executor primarily designed for processing instances of {@link
+ * java.util.concurrent.ForkJoinTask} and its subclasses.  These
+ * classes employ a work-stealing scheduler that attains high
+ * throughput for tasks conforming to restrictions that often hold in
+ * computation-intensive parallel processing.
+ *
+ * <h2>Queues</h2>
+ *
+ * The {@link java.util.concurrent.ConcurrentLinkedQueue} class
+ * supplies an efficient scalable thread-safe non-blocking FIFO queue.
+ * The {@link java.util.concurrent.ConcurrentLinkedDeque} class is
+ * similar, but additionally supports the {@link java.util.Deque}
+ * interface.
+ *
+ * <p>Five implementations in {@code java.util.concurrent} support
+ * the extended {@link java.util.concurrent.BlockingQueue}
+ * interface, that defines blocking versions of put and take:
+ * {@link java.util.concurrent.LinkedBlockingQueue},
+ * {@link java.util.concurrent.ArrayBlockingQueue},
+ * {@link java.util.concurrent.SynchronousQueue},
+ * {@link java.util.concurrent.PriorityBlockingQueue}, and
+ * {@link java.util.concurrent.DelayQueue}.
+ * The different classes cover the most common usage contexts
+ * for producer-consumer, messaging, parallel tasking, and
+ * related concurrent designs.
+ *
+ * <p>Extended interface {@link java.util.concurrent.TransferQueue},
+ * and implementation {@link java.util.concurrent.LinkedTransferQueue}
+ * introduce a synchronous {@code transfer} method (along with related
+ * features) in which a producer may optionally block awaiting its
+ * consumer.
+ *
+ * <p>The {@link java.util.concurrent.BlockingDeque} interface
+ * extends {@code BlockingQueue} to support both FIFO and LIFO
+ * (stack-based) operations.
+ * Class {@link java.util.concurrent.LinkedBlockingDeque}
+ * provides an implementation.
+ *
+ * <h2>Timing</h2>
+ *
+ * The {@link java.util.concurrent.TimeUnit} class provides
+ * multiple granularities (including nanoseconds) for
+ * specifying and controlling time-out based operations.  Most
+ * classes in the package contain operations based on time-outs
+ * in addition to indefinite waits.  In all cases that
+ * time-outs are used, the time-out specifies the minimum time
+ * that the method should wait before indicating that it
+ * timed-out.  Implementations make a &quot;best effort&quot;
+ * to detect time-outs as soon as possible after they occur.
+ * However, an indefinite amount of time may elapse between a
+ * time-out being detected and a thread actually executing
+ * again after that time-out.  All methods that accept timeout
+ * parameters treat values less than or equal to zero to mean
+ * not to wait at all.  To wait "forever", you can use a value
+ * of {@code Long.MAX_VALUE}.
+ *
+ * <h2>Synchronizers</h2>
+ *
+ * Five classes aid common special-purpose synchronization idioms.
+ * <ul>
+ *
+ * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
+ *
+ * <li>{@link java.util.concurrent.CountDownLatch} is a very simple yet
+ * very common utility for blocking until a given number of signals,
+ * events, or conditions hold.
+ *
+ * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable
+ * multiway synchronization point useful in some styles of parallel
+ * programming.
+ *
+ * <li>A {@link java.util.concurrent.Phaser} provides
+ * a more flexible form of barrier that may be used to control phased
+ * computation among multiple threads.
+ *
+ * <li>An {@link java.util.concurrent.Exchanger} allows two threads to
+ * exchange objects at a rendezvous point, and is useful in several
+ * pipeline designs.
+ *
+ * </ul>
+ *
+ * <h2>Concurrent Collections</h2>
+ *
+ * Besides Queues, this package supplies Collection implementations
+ * designed for use in multithreaded contexts:
+ * {@link java.util.concurrent.ConcurrentHashMap},
+ * {@link java.util.concurrent.ConcurrentSkipListMap},
+ * {@link java.util.concurrent.ConcurrentSkipListSet},
+ * {@link java.util.concurrent.CopyOnWriteArrayList}, and
+ * {@link java.util.concurrent.CopyOnWriteArraySet}.
+ * When many threads are expected to access a given collection, a
+ * {@code ConcurrentHashMap} is normally preferable to a synchronized
+ * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally
+ * preferable to a synchronized {@code TreeMap}.
+ * 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
+ * {@code Collections.synchronizedMap(new HashMap())} are
+ * synchronized.  But {@link
+ * java.util.concurrent.ConcurrentHashMap} is "concurrent".  A
+ * concurrent collection is thread-safe, but not governed by a
+ * single exclusion lock.  In the particular case of
+ * ConcurrentHashMap, it safely permits any number of
+ * concurrent reads as well as a large number of concurrent
+ * writes.  "Synchronized" classes can be useful when you need
+ * to prevent all access to a collection via a single lock, at
+ * the expense of poorer scalability.  In other cases in which
+ * multiple threads are expected to access a common collection,
+ * "concurrent" versions are normally preferable.  And
+ * unsynchronized collections are preferable when either
+ * collections are unshared, or are accessible only when
+ * holding other locks.
+ *
+ * <p id="Weakly">Most concurrent Collection implementations
+ * (including most Queues) also differ from the usual {@code java.util}
+ * conventions in that their {@linkplain java.util.Iterator Iterators}
+ * and {@linkplain java.util.Spliterator Spliterators} provide
+ * <em>weakly consistent</em> rather than fast-fail traversal:
+ * <ul>
+ * <li>they may proceed concurrently with other operations
+ * <li>they will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}
+ * <li>they are guaranteed to traverse elements as they existed upon
+ * construction exactly once, and may (but are not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ * </ul>
+ *
+ * <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
+ *
+ * Chapter 17 of
+ * <cite>The Java Language Specification</cite> defines the
+ * <i>happens-before</i> relation on memory operations such as reads and
+ * writes of shared variables.  The results of a write by one thread are
+ * guaranteed to be visible to a read by another thread only if the write
+ * operation <i>happens-before</i> the read operation.  The
+ * {@code synchronized} and {@code volatile} constructs, as well as the
+ * {@code Thread.start()} and {@code Thread.join()} methods, can form
+ * <i>happens-before</i> relationships.  In particular:
+ *
+ * <ul>
+ *   <li>Each action in a thread <i>happens-before</i> every action in that
+ *   thread that comes later in the program's order.
+ *
+ *   <li>An unlock ({@code synchronized} block or method exit) of a
+ *   monitor <i>happens-before</i> every subsequent lock ({@code synchronized}
+ *   block or method entry) of that same monitor.  And because
+ *   the <i>happens-before</i> relation is transitive, all actions
+ *   of a thread prior to unlocking <i>happen-before</i> all actions
+ *   subsequent to any thread locking that monitor.
+ *
+ *   <li>A write to a {@code volatile} field <i>happens-before</i> every
+ *   subsequent read of that same field.  Writes and reads of
+ *   {@code volatile} fields have similar memory consistency effects
+ *   as entering and exiting monitors, but do <em>not</em> entail
+ *   mutual exclusion locking.
+ *
+ *   <li>A call to {@code start} on a thread <i>happens-before</i> any
+ *   action in the started thread.
+ *
+ *   <li>All actions in a thread <i>happen-before</i> any other thread
+ *   successfully returns from a {@code join} on that thread.
+ *
+ * </ul>
+ *
+ * The methods of all classes in {@code java.util.concurrent} and its
+ * subpackages extend these guarantees to higher-level
+ * synchronization.  In particular:
+ *
+ * <ul>
+ *
+ *   <li>Actions in a thread prior to placing an object into any concurrent
+ *   collection <i>happen-before</i> actions subsequent to the access or
+ *   removal of that element from the collection in another thread.
+ *
+ *   <li>Actions in a thread prior to the submission of a {@code Runnable}
+ *   to an {@code Executor} <i>happen-before</i> its execution begins.
+ *   Similarly for {@code Callables} submitted to an {@code ExecutorService}.
+ *
+ *   <li>Actions taken by the asynchronous computation represented by a
+ *   {@code Future} <i>happen-before</i> actions subsequent to the
+ *   retrieval of the result via {@code Future.get()} in another thread.
+ *
+ *   <li>Actions prior to "releasing" synchronizer methods such as
+ *   {@code Lock.unlock}, {@code Semaphore.release}, and
+ *   {@code CountDownLatch.countDown} <i>happen-before</i> actions
+ *   subsequent to a successful "acquiring" method such as
+ *   {@code Lock.lock}, {@code Semaphore.acquire},
+ *   {@code Condition.await}, and {@code CountDownLatch.await} on the
+ *   same synchronizer object in another thread.
+ *
+ *   <li>For each pair of threads that successfully exchange objects via
+ *   an {@code Exchanger}, actions prior to the {@code exchange()}
+ *   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} 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}
+ *   in other threads.
+ *
+ * </ul>
+ *
+ * @jls 17.4.5 Happens-before Order
+ *
+ * @since 1.5
+ */
+package java.util.concurrent;
diff --git a/android-35/java/util/function/BiConsumer.java b/android-35/java/util/function/BiConsumer.java
new file mode 100644
index 0000000..61690e6
--- /dev/null
+++ b/android-35/java/util/function/BiConsumer.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts two input arguments and returns no
+ * result.  This is the two-arity specialization of {@link Consumer}.
+ * Unlike most other functional interfaces, {@code BiConsumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the operation
+ * @param <U> the type of the second argument to the operation
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiConsumer<T, U> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     */
+    void accept(T t, U u);
+
+    /**
+     * Returns a composed {@code BiConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code BiConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
+        Objects.requireNonNull(after);
+
+        return (l, r) -> {
+            accept(l, r);
+            after.accept(l, r);
+        };
+    }
+}
diff --git a/android-35/java/util/function/BiFunction.java b/android-35/java/util/function/BiFunction.java
new file mode 100644
index 0000000..ef75901
--- /dev/null
+++ b/android-35/java/util/function/BiFunction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts two arguments and produces a result.
+ * This is the two-arity specialization of {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiFunction<T, U, R> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    R apply(T t, U u);
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     */
+    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t, U u) -> after.apply(apply(t, u));
+    }
+}
diff --git a/android-35/java/util/function/BiPredicate.java b/android-35/java/util/function/BiPredicate.java
new file mode 100644
index 0000000..a0f19b8
--- /dev/null
+++ b/android-35/java/util/function/BiPredicate.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of two arguments.  This is
+ * the two-arity specialization of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the predicate
+ * @param <U> the type of the second argument the predicate
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiPredicate<T, U> {
+
+    /**
+     * Evaluates this predicate on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     * @return {@code true} if the input arguments match the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t, U u);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) && other.test(t, u);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default BiPredicate<T, U> negate() {
+        return (T t, U u) -> !test(t, u);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) || other.test(t, u);
+    }
+}
diff --git a/android-35/java/util/function/BinaryOperator.java b/android-35/java/util/function/BinaryOperator.java
new file mode 100644
index 0000000..a015058
--- /dev/null
+++ b/android-35/java/util/function/BinaryOperator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+import java.util.Comparator;
+
+/**
+ * Represents an operation upon two operands of the same type, producing a result
+ * of the same type as the operands.  This is a specialization of
+ * {@link BiFunction} for the case where the operands and the result are all of
+ * the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the operands and result of the operator
+ *
+ * @see BiFunction
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BinaryOperator<T> extends BiFunction<T,T,T> {
+    /**
+     * Returns a {@link BinaryOperator} which returns the lesser of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the lesser of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
+    }
+
+    /**
+     * Returns a {@link BinaryOperator} which returns the greater of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the greater of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
+    }
+}
diff --git a/android-35/java/util/function/BooleanSupplier.java b/android-35/java/util/function/BooleanSupplier.java
new file mode 100644
index 0000000..2faff30
--- /dev/null
+++ b/android-35/java/util/function/BooleanSupplier.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+
+/**
+ * Represents a supplier of {@code boolean}-valued results.  This is the
+ * {@code boolean}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsBoolean()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BooleanSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    boolean getAsBoolean();
+}
diff --git a/android-35/java/util/function/Consumer.java b/android-35/java/util/function/Consumer.java
new file mode 100644
index 0000000..a2481fe
--- /dev/null
+++ b/android-35/java/util/function/Consumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single input argument and returns no
+ * result. Unlike most other functional interfaces, {@code Consumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object)}.
+ *
+ * @param <T> the type of the input to the operation
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Consumer<T> {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param t the input argument
+     */
+    void accept(T t);
+
+    /**
+     * Returns a composed {@code Consumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code Consumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default Consumer<T> andThen(Consumer<? super T> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/android-35/java/util/function/DoubleBinaryOperator.java b/android-35/java/util/function/DoubleBinaryOperator.java
new file mode 100644
index 0000000..839433d
--- /dev/null
+++ b/android-35/java/util/function/DoubleBinaryOperator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code double}-valued operands and producing a
+ * {@code double}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double, double)}.
+ *
+ * @see BinaryOperator
+ * @see DoubleUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleBinaryOperator {
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    double applyAsDouble(double left, double right);
+}
diff --git a/android-35/java/util/function/DoubleConsumer.java b/android-35/java/util/function/DoubleConsumer.java
new file mode 100644
index 0000000..046360c
--- /dev/null
+++ b/android-35/java/util/function/DoubleConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code double}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code double}.  Unlike most other functional interfaces,
+ * {@code DoubleConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(double)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(double value);
+
+    /**
+     * Returns a composed {@code DoubleConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code DoubleConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default DoubleConsumer andThen(DoubleConsumer after) {
+        Objects.requireNonNull(after);
+        return (double t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/android-35/java/util/function/DoubleFunction.java b/android-35/java/util/function/DoubleFunction.java
new file mode 100644
index 0000000..a8bb57d
--- /dev/null
+++ b/android-35/java/util/function/DoubleFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * result.  This is the {@code double}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(double)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(double value);
+}
diff --git a/android-35/java/util/function/DoublePredicate.java b/android-35/java/util/function/DoublePredicate.java
new file mode 100644
index 0000000..1df1762
--- /dev/null
+++ b/android-35/java/util/function/DoublePredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code double}-valued
+ * argument. This is the {@code double}-consuming primitive type specialization
+ * of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(double)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoublePredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(double value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate and(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default DoublePredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate or(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/android-35/java/util/function/DoubleSupplier.java b/android-35/java/util/function/DoubleSupplier.java
new file mode 100644
index 0000000..5169011
--- /dev/null
+++ b/android-35/java/util/function/DoubleSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code double}-valued results.  This is the
+ * {@code double}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsDouble()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    double getAsDouble();
+}
diff --git a/android-35/java/util/function/DoubleToIntFunction.java b/android-35/java/util/function/DoubleToIntFunction.java
new file mode 100644
index 0000000..a23f033
--- /dev/null
+++ b/android-35/java/util/function/DoubleToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces an
+ * int-valued result.  This is the {@code double}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(double value);
+}
diff --git a/android-35/java/util/function/DoubleToLongFunction.java b/android-35/java/util/function/DoubleToLongFunction.java
new file mode 100644
index 0000000..436369c
--- /dev/null
+++ b/android-35/java/util/function/DoubleToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * long-valued result.  This is the {@code double}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(double value);
+}
diff --git a/android-35/java/util/function/DoubleUnaryOperator.java b/android-35/java/util/function/DoubleUnaryOperator.java
new file mode 100644
index 0000000..2f134c9
--- /dev/null
+++ b/android-35/java/util/function/DoubleUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code double}-valued operand that produces
+ * a {@code double}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    double applyAsDouble(double operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator compose(DoubleUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (double v) -> applyAsDouble(before.applyAsDouble(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator andThen(DoubleUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (double t) -> after.applyAsDouble(applyAsDouble(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static DoubleUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/android-35/java/util/function/Function.java b/android-35/java/util/function/Function.java
new file mode 100644
index 0000000..7bcbfd0
--- /dev/null
+++ b/android-35/java/util/function/Function.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts one argument and produces a result.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ * @param <R> the type of the result of the function
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Function<T, R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @return the function result
+     */
+    R apply(T t);
+
+    /**
+     * Returns a composed function that first applies the {@code before}
+     * function to its input, and then applies this function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of input to the {@code before} function, and to the
+     *           composed function
+     * @param before the function to apply before this function is applied
+     * @return a composed function that first applies the {@code before}
+     * function and then applies this function
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(Function)
+     */
+    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> apply(before.apply(v));
+    }
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(Function)
+     */
+    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> after.apply(apply(t));
+    }
+
+    /**
+     * Returns a function that always returns its input argument.
+     *
+     * @param <T> the type of the input and output objects to the function
+     * @return a function that always returns its input argument
+     */
+    static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+}
diff --git a/android-35/java/util/function/IntBinaryOperator.java b/android-35/java/util/function/IntBinaryOperator.java
new file mode 100644
index 0000000..21bb946
--- /dev/null
+++ b/android-35/java/util/function/IntBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code int}-valued operands and producing an
+ * {@code int}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int, int)}.
+ *
+ * @see BinaryOperator
+ * @see IntUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    int applyAsInt(int left, int right);
+}
diff --git a/android-35/java/util/function/IntConsumer.java b/android-35/java/util/function/IntConsumer.java
new file mode 100644
index 0000000..d8daf73
--- /dev/null
+++ b/android-35/java/util/function/IntConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code int}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code int}.  Unlike most other functional interfaces,
+ * {@code IntConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(int)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(int value);
+
+    /**
+     * Returns a composed {@code IntConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code IntConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default IntConsumer andThen(IntConsumer after) {
+        Objects.requireNonNull(after);
+        return (int t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/android-35/java/util/function/IntFunction.java b/android-35/java/util/function/IntFunction.java
new file mode 100644
index 0000000..de10df4
--- /dev/null
+++ b/android-35/java/util/function/IntFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * result.  This is the {@code int}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(int)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(int value);
+}
diff --git a/android-35/java/util/function/IntPredicate.java b/android-35/java/util/function/IntPredicate.java
new file mode 100644
index 0000000..5a9bd46
--- /dev/null
+++ b/android-35/java/util/function/IntPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code int}-valued
+ * argument. This is the {@code int}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(int)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(int value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate and(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default IntPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate or(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/android-35/java/util/function/IntSupplier.java b/android-35/java/util/function/IntSupplier.java
new file mode 100644
index 0000000..89489c5
--- /dev/null
+++ b/android-35/java/util/function/IntSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code int}-valued results.  This is the
+ * {@code int}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsInt()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    int getAsInt();
+}
diff --git a/android-35/java/util/function/IntToDoubleFunction.java b/android-35/java/util/function/IntToDoubleFunction.java
new file mode 100644
index 0000000..5012154
--- /dev/null
+++ b/android-35/java/util/function/IntToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * double-valued result.  This is the {@code int}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(int value);
+}
diff --git a/android-35/java/util/function/IntToLongFunction.java b/android-35/java/util/function/IntToLongFunction.java
new file mode 100644
index 0000000..6c52faa
--- /dev/null
+++ b/android-35/java/util/function/IntToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * long-valued result.  This is the {@code int}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(int value);
+}
diff --git a/android-35/java/util/function/IntUnaryOperator.java b/android-35/java/util/function/IntUnaryOperator.java
new file mode 100644
index 0000000..300fc14
--- /dev/null
+++ b/android-35/java/util/function/IntUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code int}-valued operand that produces
+ * an {@code int}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    int applyAsInt(int operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(IntUnaryOperator)
+     */
+    default IntUnaryOperator compose(IntUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (int v) -> applyAsInt(before.applyAsInt(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(IntUnaryOperator)
+     */
+    default IntUnaryOperator andThen(IntUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (int t) -> after.applyAsInt(applyAsInt(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static IntUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/android-35/java/util/function/LongBinaryOperator.java b/android-35/java/util/function/LongBinaryOperator.java
new file mode 100644
index 0000000..287481e
--- /dev/null
+++ b/android-35/java/util/function/LongBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code long}-valued operands and producing a
+ * {@code long}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long, long)}.
+ *
+ * @see BinaryOperator
+ * @see LongUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    long applyAsLong(long left, long right);
+}
diff --git a/android-35/java/util/function/LongConsumer.java b/android-35/java/util/function/LongConsumer.java
new file mode 100644
index 0000000..b59d030
--- /dev/null
+++ b/android-35/java/util/function/LongConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code long}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code long}.  Unlike most other functional interfaces,
+ * {@code LongConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(long)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(long value);
+
+    /**
+     * Returns a composed {@code LongConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code LongConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default LongConsumer andThen(LongConsumer after) {
+        Objects.requireNonNull(after);
+        return (long t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/android-35/java/util/function/LongFunction.java b/android-35/java/util/function/LongFunction.java
new file mode 100644
index 0000000..2030c04
--- /dev/null
+++ b/android-35/java/util/function/LongFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * result.  This is the {@code long}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(long)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(long value);
+}
diff --git a/android-35/java/util/function/LongPredicate.java b/android-35/java/util/function/LongPredicate.java
new file mode 100644
index 0000000..5afdd41
--- /dev/null
+++ b/android-35/java/util/function/LongPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code long}-valued
+ * argument. This is the {@code long}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(long)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(long value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate and(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default LongPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate or(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/android-35/java/util/function/LongSupplier.java b/android-35/java/util/function/LongSupplier.java
new file mode 100644
index 0000000..513d906
--- /dev/null
+++ b/android-35/java/util/function/LongSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code long}-valued results.  This is the
+ * {@code long}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsLong()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    long getAsLong();
+}
diff --git a/android-35/java/util/function/LongToDoubleFunction.java b/android-35/java/util/function/LongToDoubleFunction.java
new file mode 100644
index 0000000..9d0831f
--- /dev/null
+++ b/android-35/java/util/function/LongToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * double-valued result.  This is the {@code long}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(long value);
+}
diff --git a/android-35/java/util/function/LongToIntFunction.java b/android-35/java/util/function/LongToIntFunction.java
new file mode 100644
index 0000000..d1d6c34
--- /dev/null
+++ b/android-35/java/util/function/LongToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces an
+ * int-valued result.  This is the {@code long}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(long value);
+}
diff --git a/android-35/java/util/function/LongUnaryOperator.java b/android-35/java/util/function/LongUnaryOperator.java
new file mode 100644
index 0000000..e2bbddd
--- /dev/null
+++ b/android-35/java/util/function/LongUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code long}-valued operand that produces
+ * a {@code long}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    long applyAsLong(long operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(LongUnaryOperator)
+     */
+    default LongUnaryOperator compose(LongUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (long v) -> applyAsLong(before.applyAsLong(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(LongUnaryOperator)
+     */
+    default LongUnaryOperator andThen(LongUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (long t) -> after.applyAsLong(applyAsLong(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static LongUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/android-35/java/util/function/ObjDoubleConsumer.java b/android-35/java/util/function/ObjDoubleConsumer.java
new file mode 100644
index 0000000..d551fc7
--- /dev/null
+++ b/android-35/java/util/function/ObjDoubleConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code double}-valued argument, and returns no result.  This is the
+ * {@code (reference, double)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjDoubleConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, double)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjDoubleConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, double value);
+}
diff --git a/android-35/java/util/function/ObjIntConsumer.java b/android-35/java/util/function/ObjIntConsumer.java
new file mode 100644
index 0000000..2eb32d6
--- /dev/null
+++ b/android-35/java/util/function/ObjIntConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code int}-valued argument, and returns no result.  This is the
+ * {@code (reference, int)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjIntConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, int)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjIntConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, int value);
+}
diff --git a/android-35/java/util/function/ObjLongConsumer.java b/android-35/java/util/function/ObjLongConsumer.java
new file mode 100644
index 0000000..f40eea2
--- /dev/null
+++ b/android-35/java/util/function/ObjLongConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code long}-valued argument, and returns no result.  This is the
+ * {@code (reference, long)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjLongConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, long)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjLongConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, long value);
+}
diff --git a/android-35/java/util/function/Predicate.java b/android-35/java/util/function/Predicate.java
new file mode 100644
index 0000000..b34febb
--- /dev/null
+++ b/android-35/java/util/function/Predicate.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one argument.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object)}.
+ *
+ * @param <T> the type of the input to the predicate
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Predicate<T> {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param t the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> and(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) && other.test(t);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default Predicate<T> negate() {
+        return (t) -> !test(t);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> or(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) || other.test(t);
+    }
+
+    /**
+     * Returns a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}.
+     *
+     * @param <T> the type of arguments to the predicate
+     * @param targetRef the object reference with which to compare for equality,
+     *               which may be {@code null}
+     * @return a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}
+     */
+    static <T> Predicate<T> isEqual(Object targetRef) {
+        return (null == targetRef)
+                ? Objects::isNull
+                : object -> targetRef.equals(object);
+    }
+
+    /**
+     * Returns a predicate that is the negation of the supplied predicate.
+     * This is accomplished by returning result of the calling
+     * {@code target.negate()}.
+     *
+     * @param <T>     the type of arguments to the specified predicate
+     * @param target  predicate to negate
+     *
+     * @return a predicate that negates the results of the supplied
+     *         predicate
+     *
+     * @throws NullPointerException if target is null
+     *
+     * @since 11
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Predicate<T> not(Predicate<? super T> target) {
+        Objects.requireNonNull(target);
+        return (Predicate<T>)target.negate();
+    }
+}
diff --git a/android-35/java/util/function/Supplier.java b/android-35/java/util/function/Supplier.java
new file mode 100644
index 0000000..b87777e
--- /dev/null
+++ b/android-35/java/util/function/Supplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of results.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #get()}.
+ *
+ * @param <T> the type of results supplied by this supplier
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Supplier<T> {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    T get();
+}
diff --git a/android-35/java/util/function/ToDoubleBiFunction.java b/android-35/java/util/function/ToDoubleBiFunction.java
new file mode 100644
index 0000000..d0efcee
--- /dev/null
+++ b/android-35/java/util/function/ToDoubleBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a double-valued
+ * result.  This is the {@code double}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    double applyAsDouble(T t, U u);
+}
diff --git a/android-35/java/util/function/ToDoubleFunction.java b/android-35/java/util/function/ToDoubleFunction.java
new file mode 100644
index 0000000..29bf988
--- /dev/null
+++ b/android-35/java/util/function/ToDoubleFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a double-valued result.  This is the
+ * {@code double}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(T value);
+}
diff --git a/android-35/java/util/function/ToIntBiFunction.java b/android-35/java/util/function/ToIntBiFunction.java
new file mode 100644
index 0000000..0e28d26
--- /dev/null
+++ b/android-35/java/util/function/ToIntBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces an int-valued
+ * result.  This is the {@code int}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    int applyAsInt(T t, U u);
+}
diff --git a/android-35/java/util/function/ToIntFunction.java b/android-35/java/util/function/ToIntFunction.java
new file mode 100644
index 0000000..5768242
--- /dev/null
+++ b/android-35/java/util/function/ToIntFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces an int-valued result.  This is the
+ * {@code int}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(T value);
+}
diff --git a/android-35/java/util/function/ToLongBiFunction.java b/android-35/java/util/function/ToLongBiFunction.java
new file mode 100644
index 0000000..8b5ed7e
--- /dev/null
+++ b/android-35/java/util/function/ToLongBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a long-valued
+ * result.  This is the {@code long}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    long applyAsLong(T t, U u);
+}
diff --git a/android-35/java/util/function/ToLongFunction.java b/android-35/java/util/function/ToLongFunction.java
new file mode 100644
index 0000000..eefb617
--- /dev/null
+++ b/android-35/java/util/function/ToLongFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a long-valued result.  This is the
+ * {@code long}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(T value);
+}
diff --git a/android-35/java/util/function/UnaryOperator.java b/android-35/java/util/function/UnaryOperator.java
new file mode 100644
index 0000000..c4aa749
--- /dev/null
+++ b/android-35/java/util/function/UnaryOperator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation on a single operand that produces a result of the
+ * same type as its operand.  This is a specialization of {@code Function} for
+ * the case where the operand and result are of the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the operand and result of the operator
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface UnaryOperator<T> extends Function<T, T> {
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @param <T> the type of the input and output of the operator
+     * @return a unary operator that always returns its input argument
+     */
+    static <T> UnaryOperator<T> identity() {
+        return t -> t;
+    }
+}
diff --git a/android-35/java/util/function/package-info.java b/android-35/java/util/function/package-info.java
new file mode 100644
index 0000000..905fa7d
--- /dev/null
+++ b/android-35/java/util/function/package-info.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <em>Functional interfaces</em> provide target types for lambda expressions
+ * and method references.  Each functional interface has a single abstract
+ * method, called the <em>functional method</em> for that functional interface,
+ * to which the lambda expression's parameter and return types are matched or
+ * adapted.  Functional interfaces can provide a target type in multiple
+ * contexts, such as assignment context, method invocation, or cast context:
+ *
+ * <pre>{@code
+ *     // Assignment context
+ *     Predicate<String> p = String::isEmpty;
+ *
+ *     // Method invocation context
+ *     stream.filter(e -> e.getSize() > 10)...
+ *
+ *     // Cast context
+ *     stream.map((ToIntFunction) e -> e.getSize())...
+ * }</pre>
+ *
+ * <p>The interfaces in this package are general purpose functional interfaces
+ * used by the JDK, and are available to be used by user code as well.  While
+ * they do not identify a complete set of function shapes to which lambda
+ * expressions might be adapted, they provide enough to cover common
+ * requirements. Other functional interfaces provided for specific purposes,
+ * such as {@link java.io.FileFilter}, are defined in the packages where they
+ * are used.
+ *
+ * <p>The interfaces in this package are annotated with
+ * {@link java.lang.FunctionalInterface}. This annotation is not a requirement
+ * for the compiler to recognize an interface as a functional interface, but
+ * merely an aid to capture design intent and enlist the help of the compiler in
+ * identifying accidental violations of design intent.
+ *
+ * <p>Functional interfaces often represent abstract concepts like functions,
+ * actions, or predicates.  In documenting functional interfaces, or referring
+ * to variables typed as functional interfaces, it is common to refer directly
+ * to those abstract concepts, for example using "this function" instead of
+ * "the function represented by this object".  When an API method is said to
+ * accept or return a functional interface in this manner, such as "applies the
+ * provided function to...", this is understood to mean a <i>non-null</i>
+ * reference to an object implementing the appropriate functional interface,
+ * unless potential nullity is explicitly specified.
+ *
+ * <p>The functional interfaces in this package follow an extensible naming
+ * convention, as follows:
+ *
+ * <ul>
+ *     <li>There are several basic function shapes, including
+ *     {@link java.util.function.Function} (unary function from {@code T} to {@code R}),
+ *     {@link java.util.function.Consumer} (unary function from {@code T} to {@code void}),
+ *     {@link java.util.function.Predicate} (unary function from {@code T} to {@code boolean}),
+ *     and {@link java.util.function.Supplier} (nullary function to {@code R}).
+ *     </li>
+ *
+ *     <li>Function shapes have a natural arity based on how they are most
+ *     commonly used.  The basic shapes can be modified by an arity prefix to
+ *     indicate a different arity, such as
+ *     {@link java.util.function.BiFunction} (binary function from {@code T} and
+ *     {@code U} to {@code R}).
+ *     </li>
+ *
+ *     <li>There are additional derived function shapes which extend the basic
+ *     function shapes, including {@link java.util.function.UnaryOperator}
+ *     (extends {@code Function}) and {@link java.util.function.BinaryOperator}
+ *     (extends {@code BiFunction}).
+ *     </li>
+ *
+ *     <li>Type parameters of functional interfaces can be specialized to
+ *     primitives with additional type prefixes.  To specialize the return type
+ *     for a type that has both generic return type and generic arguments, we
+ *     prefix {@code ToXxx}, as in {@link java.util.function.ToIntFunction}.
+ *     Otherwise, type arguments are specialized left-to-right, as in
+ *     {@link java.util.function.DoubleConsumer}
+ *     or {@link java.util.function.ObjIntConsumer}.
+ *     (The type prefix {@code Obj} is used to indicate that we don't want to
+ *     specialize this parameter, but want to move on to the next parameter,
+ *     as in {@link java.util.function.ObjIntConsumer}.)
+ *     These schemes can be combined, as in {@code IntToDoubleFunction}.
+ *     </li>
+ *
+ *     <li>If there are specialization prefixes for all arguments, the arity
+ *     prefix may be left out (as in {@link java.util.function.ObjIntConsumer}).
+ *     </li>
+ * </ul>
+ *
+ * @see java.lang.FunctionalInterface
+ * @since 1.8
+ */
+package java.util.function;
diff --git a/android-35/java/util/jar/Attributes.java b/android-35/java/util/jar/Attributes.java
new file mode 100644
index 0000000..0df10d8
--- /dev/null
+++ b/android-35/java/util/jar/Attributes.java
@@ -0,0 +1,764 @@
+/*
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import jdk.internal.vm.annotation.Stable;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * The Attributes class maps Manifest attribute names to associated string
+ * values. Valid attribute names are case-insensitive, are restricted to
+ * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70
+ * characters in length. There must be a colon and a SPACE after the name;
+ * the combined length will not exceed 72 characters.
+ * Attribute values can contain any characters and
+ * will be UTF8-encoded when written to the output stream.  See the
+ * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a>
+ * for more information about valid attribute names and values.
+ *
+ * <p>This map and its views have a predictable iteration order, namely the
+ * order that keys were inserted into the map, as with {@link LinkedHashMap}.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @since   1.2
+ */
+public class Attributes implements Map<Object,Object>, Cloneable {
+    /**
+     * The attribute name-value mappings.
+     */
+    protected Map<Object,Object> map;
+
+    /**
+     * Constructs a new, empty Attributes object with default size.
+     */
+    public Attributes() {
+        this(11);
+    }
+
+    /**
+     * Constructs a new, empty Attributes object with the specified
+     * initial size.
+     *
+     * @param size the initial number of attributes
+     */
+    public Attributes(int size) {
+        map = new LinkedHashMap<>(size);
+    }
+
+    /**
+     * Constructs a new Attributes object with the same attribute name-value
+     * mappings as in the specified Attributes.
+     *
+     * @param attr the specified Attributes
+     */
+    public Attributes(Attributes attr) {
+        map = new LinkedHashMap<>(attr);
+    }
+
+
+    /**
+     * Returns the value of the specified attribute name, or null if the
+     * attribute name was not found.
+     *
+     * @param name the attribute name
+     * @return the value of the specified attribute name, or null if
+     *         not found.
+     */
+    public Object get(Object name) {
+        return map.get(name);
+    }
+
+    /**
+     * Returns the value of the specified attribute name, specified as
+     * a string, or null if the attribute was not found. The attribute
+     * name is case-insensitive.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)get(new Attributes.Name((String)name));
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @return the String value of the specified attribute name, or null if
+     *         not found.
+     * @throws IllegalArgumentException if the attribute name is invalid
+     */
+    public String getValue(String name) {
+        return (String)get(Name.of(name));
+    }
+
+    /**
+     * Returns the value of the specified Attributes.Name, or null if the
+     * attribute was not found.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *     return (String)get(name);
+     * </pre>
+     *
+     * @param name the Attributes.Name object
+     * @return the String value of the specified Attribute.Name, or null if
+     *         not found.
+     */
+    public String getValue(Name name) {
+        return (String)get(name);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name
+     * (key) in this Map. If the Map previously contained a mapping for
+     * the attribute name, the old value is replaced.
+     *
+     * @param name the attribute name
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @throws    ClassCastException if the name is not a Attributes.Name
+     *            or the value is not a String
+     */
+    public Object put(Object name, Object value) {
+        return map.put((Attributes.Name)name, (String)value);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name,
+     * specified as a String. The attributes name is case-insensitive.
+     * If the Map previously contained a mapping for the attribute name,
+     * the old value is replaced.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)put(new Attributes.Name(name), value);
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @throws    IllegalArgumentException if the attribute name is invalid
+     */
+    public String putValue(String name, String value) {
+        return (String)put(Name.of(name), value);
+    }
+
+    /**
+     * Removes the attribute with the specified name (key) from this Map.
+     * Returns the previous attribute value, or null if none.
+     *
+     * @param name attribute name
+     * @return the previous value of the attribute, or null if none
+     */
+    public Object remove(Object name) {
+        return map.remove(name);
+    }
+
+    /**
+     * Returns true if this Map maps one or more attribute names (keys)
+     * to the specified value.
+     *
+     * @param value the attribute value
+     * @return true if this Map maps one or more attribute names to
+     *         the specified value
+     */
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    /**
+     * Returns true if this Map contains the specified attribute name (key).
+     *
+     * @param name the attribute name
+     * @return true if this Map contains the specified attribute name
+     */
+    public boolean containsKey(Object name) {
+        return map.containsKey(name);
+    }
+
+    /**
+     * Copies all of the attribute name-value mappings from the specified
+     * Attributes to this Map. Duplicate mappings will be replaced.
+     *
+     * @param attr the Attributes to be stored in this map
+     * @throws    ClassCastException if attr is not an Attributes
+     */
+    public void putAll(Map<?,?> attr) {
+        // ## javac bug?
+        if (!Attributes.class.isInstance(attr))
+            throw new ClassCastException();
+        for (Map.Entry<?,?> me : (attr).entrySet())
+            put(me.getKey(), me.getValue());
+    }
+
+    /**
+     * Removes all attributes from this Map.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns the number of attributes in this Map.
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns true if this Map contains no attributes.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns a Set view of the attribute names (keys) contained in this Map.
+     */
+    public Set<Object> keySet() {
+        return map.keySet();
+    }
+
+    /**
+     * Returns a Collection view of the attribute values contained in this Map.
+     */
+    public Collection<Object> values() {
+        return map.values();
+    }
+
+    /**
+     * Returns a Collection view of the attribute name-value mappings
+     * contained in this Map.
+     */
+    public Set<Map.Entry<Object,Object>> entrySet() {
+        return map.entrySet();
+    }
+
+    /**
+     * Compares the specified object to the underlying
+     * {@linkplain Attributes#map map} for equality.
+     * Returns true if the given object is also a Map
+     * and the two maps represent the same mappings.
+     *
+     * @param o the Object to be compared
+     * @return true if the specified Object is equal to this Map
+     */
+    public boolean equals(Object o) {
+        return map.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Map.
+     */
+    public int hashCode() {
+        return map.hashCode();
+    }
+
+    /**
+     * Returns a copy of the Attributes, implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Attributes(this); }
+     * </pre>
+     * Since the attribute names and values are themselves immutable,
+     * the Attributes returned can be safely modified without affecting
+     * the original.
+     */
+    public Object clone() {
+        return new Attributes(this);
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream.
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+    void write(DataOutputStream out) throws IOException {
+        StringBuilder buffer = new StringBuilder(72);
+        for (Entry<Object, Object> e : entrySet()) {
+            buffer.setLength(0);
+            buffer.append(e.getKey().toString());
+            buffer.append(": ");
+            buffer.append(e.getValue());
+            Manifest.println72(out, buffer.toString());
+        }
+        Manifest.println(out); // empty line after individual section
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream,
+     * make sure to write out the MANIFEST_VERSION or SIGNATURE_VERSION
+     * attributes first.
+     *
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+    void writeMain(DataOutputStream out) throws IOException {
+        StringBuilder buffer = new StringBuilder(72);
+
+        // write out the *-Version header first, if it exists
+        String vername = Name.MANIFEST_VERSION.toString();
+        String version = getValue(vername);
+        if (version == null) {
+            vername = Name.SIGNATURE_VERSION.toString();
+            version = getValue(vername);
+        }
+
+        if (version != null) {
+            buffer.append(vername);
+            buffer.append(": ");
+            buffer.append(version);
+            out.write(buffer.toString().getBytes(UTF_8));
+            Manifest.println(out);
+        }
+
+        // write out all attributes except for the version
+        // we wrote out earlier
+        for (Entry<Object, Object> e : entrySet()) {
+            String name = ((Name) e.getKey()).toString();
+            if ((version != null) && !(name.equalsIgnoreCase(vername))) {
+                buffer.setLength(0);
+                buffer.append(name);
+                buffer.append(": ");
+                buffer.append(e.getValue());
+                Manifest.println72(out, buffer.toString());
+            }
+        }
+
+        Manifest.println(out); // empty line after main attributes section
+    }
+
+    /*
+     * Reads attributes from the specified input stream.
+     */
+    void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException {
+        read(is, lbuf, null, 0);
+    }
+
+    int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int lineNumber) throws IOException {
+        String name = null, value;
+        ByteArrayOutputStream fullLine = new ByteArrayOutputStream();
+
+        int len;
+        while ((len = is.readLine(lbuf)) != -1) {
+            boolean lineContinued = false;
+            byte c = lbuf[--len];
+            lineNumber++;
+
+            if (c != '\n' && c != '\r') {
+                throw new IOException("line too long ("
+                            + Manifest.getErrorPosition(filename, lineNumber) + ")");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0) {
+                break;
+            }
+            int i = 0;
+            if (lbuf[0] == ' ') {
+                // continuation of previous line
+                if (name == null) {
+                    throw new IOException("misplaced continuation line ("
+                                + Manifest.getErrorPosition(filename, lineNumber) + ")");
+                }
+                lineContinued = true;
+                fullLine.write(lbuf, 1, len - 1);
+                if (is.peek() == ' ') {
+                    continue;
+                }
+                value = fullLine.toString(UTF_8);
+                fullLine.reset();
+            } else {
+                while (lbuf[i++] != ':') {
+                    if (i >= len) {
+                        throw new IOException("invalid header field ("
+                                    + Manifest.getErrorPosition(filename, lineNumber) + ")");
+                    }
+                }
+                if (lbuf[i++] != ' ') {
+                    throw new IOException("invalid header field ("
+                                + Manifest.getErrorPosition(filename, lineNumber) + ")");
+                }
+                name = new String(lbuf, 0, i - 2, UTF_8);
+                if (is.peek() == ' ') {
+                    fullLine.reset();
+                    fullLine.write(lbuf, i, len - i);
+                    continue;
+                }
+                value = new String(lbuf, i, len - i, UTF_8);
+            }
+            try {
+                if ((putValue(name, value) != null) && (!lineContinued)) {
+                    PlatformLogger.getLogger("java.util.jar").warning(
+                                     "Duplicate name in Manifest: " + name
+                                     + ".\n"
+                                     + "Ensure that the manifest does not "
+                                     + "have duplicate entries, and\n"
+                                     + "that blank lines separate "
+                                     + "individual sections in both your\n"
+                                     + "manifest and in the META-INF/MANIFEST.MF "
+                                     + "entry in the jar file.");
+                }
+            } catch (IllegalArgumentException e) {
+                throw new IOException("invalid header field name: " + name
+                            + " (" + Manifest.getErrorPosition(filename, lineNumber) + ")");
+            }
+        }
+        return lineNumber;
+    }
+
+    /**
+     * The Attributes.Name class represents an attribute name stored in
+     * this Map. Valid attribute names are case-insensitive, are restricted
+     * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed
+     * 70 characters in length. Attribute values can contain any characters
+     * and will be UTF8-encoded when written to the output stream.  See the
+     * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a>
+     * for more information about valid attribute names and values.
+     */
+    public static class Name {
+        private final String name;
+        private final int hashCode;
+
+        /**
+         * Avoid allocation for common Names
+         */
+        private static @Stable Map<String, Name> KNOWN_NAMES;
+
+        static final Name of(String name) {
+            Name n = KNOWN_NAMES.get(name);
+            if (n != null) {
+                return n;
+            }
+            return new Name(name);
+        }
+
+        /**
+         * Constructs a new attribute name using the given string name.
+         *
+         * @param name the attribute string name
+         * @throws    IllegalArgumentException if the attribute name was
+         *            invalid
+         * @throws    NullPointerException if the attribute name was null
+         */
+        public Name(String name) {
+            this.hashCode = hash(name);
+            this.name = name.intern();
+        }
+
+        // Checks the string is valid
+        private final int hash(String name) {
+            Objects.requireNonNull(name, "name");
+            int len = name.length();
+            if (len > 70 || len == 0) {
+                throw new IllegalArgumentException(name);
+            }
+            // Calculate hash code case insensitively
+            int h = 0;
+            for (int i = 0; i < len; i++) {
+                char c = name.charAt(i);
+                if (c >= 'a' && c <= 'z') {
+                    // hashcode must be identical for upper and lower case
+                    h = h * 31 + (c - 0x20);
+                } else if ((c >= 'A' && c <= 'Z' ||
+                        c >= '0' && c <= '9' ||
+                        c == '_' || c == '-')) {
+                    h = h * 31 + c;
+                } else {
+                    throw new IllegalArgumentException(name);
+                }
+            }
+            return h;
+        }
+
+        /**
+         * Compares this attribute name to another for equality.
+         * @param o the object to compare
+         * @return true if this attribute name is equal to the
+         *         specified attribute object
+         */
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            // TODO(b/248243024) revert this.
+            /*
+            return o instanceof Name other
+                    && other.name.equalsIgnoreCase(name);
+            */
+            if (o instanceof Name) {
+                return ((Name) o).name.equalsIgnoreCase(name);
+            }
+            return false;
+        }
+
+        /**
+         * Computes the hash value for this attribute name.
+         */
+        public int hashCode() {
+            return hashCode;
+        }
+
+        /**
+         * Returns the attribute name as a String.
+         */
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * {@code Name} object for {@code Manifest-Version}
+         * manifest attribute. This attribute indicates the version number
+         * of the manifest standard to which a JAR file's manifest conforms.
+         * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name MANIFEST_VERSION;
+
+        /**
+         * {@code Name} object for {@code Signature-Version}
+         * manifest attribute used when signing JAR files.
+         * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name SIGNATURE_VERSION;
+
+        /**
+         * {@code Name} object for {@code Content-Type}
+         * manifest attribute.
+         */
+        public static final Name CONTENT_TYPE;
+
+        /**
+         * {@code Name} object for {@code Class-Path}
+         * manifest attribute.
+         * @see <a href="{@docRoot}/../specs/jar/jar.html#class-path-attribute">
+         *      JAR file specification</a>
+         */
+        public static final Name CLASS_PATH;
+
+        /**
+         * {@code Name} object for {@code Main-Class} manifest
+         * attribute used for launching applications packaged in JAR files.
+         * The {@code Main-Class} attribute is used in conjunction
+         * with the {@code -jar} command-line option of the
+         * {@code java} application launcher.
+         */
+        public static final Name MAIN_CLASS;
+
+        /**
+         * {@code Name} object for {@code Sealed} manifest attribute
+         * used for sealing.
+         * @see <a href="{@docRoot}/../specs/jar/jar.html#package-sealing">
+         *      Package Sealing</a>
+         */
+        public static final Name SEALED;
+
+        /**
+         * {@code Name} object for {@code Extension-List} manifest attribute
+         * used for the extension mechanism that is no longer supported.
+         */
+        public static final Name EXTENSION_LIST;
+
+        /**
+         * {@code Name} object for {@code Extension-Name} manifest attribute
+         * used for the extension mechanism that is no longer supported.
+         */
+        public static final Name EXTENSION_NAME;
+
+        /**
+         * {@code Name} object for {@code Extension-Installation} manifest attribute.
+         *
+         * @deprecated Extension mechanism is no longer supported.
+         */
+        @Deprecated
+        public static final Name EXTENSION_INSTALLATION;
+
+        /**
+         * {@code Name} object for {@code Implementation-Title}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name IMPLEMENTATION_TITLE;
+
+        /**
+         * {@code Name} object for {@code Implementation-Version}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name IMPLEMENTATION_VERSION;
+
+        /**
+         * {@code Name} object for {@code Implementation-Vendor}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name IMPLEMENTATION_VENDOR;
+
+        /**
+         * {@code Name} object for {@code Implementation-Vendor-Id}
+         * manifest attribute.
+         *
+         * @deprecated Extension mechanism is no longer supported.
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_VENDOR_ID;
+
+        /**
+         * {@code Name} object for {@code Implementation-URL}
+         * manifest attribute.
+         *
+         * @deprecated Extension mechanism is no longer supported.
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_URL;
+
+        /**
+         * {@code Name} object for {@code Specification-Title}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name SPECIFICATION_TITLE;
+
+        /**
+         * {@code Name} object for {@code Specification-Version}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name SPECIFICATION_VERSION;
+
+        /**
+         * {@code Name} object for {@code Specification-Vendor}
+         * manifest attribute used for package versioning.
+         */
+        public static final Name SPECIFICATION_VENDOR;
+
+        // Android-removed: multi-release JARs are not supported.
+        /*
+         * {@code Name} object for {@code Multi-Release}
+         * manifest attribute that indicates this is a multi-release JAR file.
+         *
+         * @since   9
+         *
+        public static final Name MULTI_RELEASE;
+        */
+
+        private static void addName(Map<String, Name> names, Name name) {
+            names.put(name.name, name);
+        }
+
+        static {
+
+            // Android-removed: CDS is not supported on Android.
+            // CDS.initializeFromArchive(Attributes.Name.class);
+
+            if (KNOWN_NAMES == null) {
+                MANIFEST_VERSION = new Name("Manifest-Version");
+                SIGNATURE_VERSION = new Name("Signature-Version");
+                CONTENT_TYPE = new Name("Content-Type");
+                CLASS_PATH = new Name("Class-Path");
+                MAIN_CLASS = new Name("Main-Class");
+                SEALED = new Name("Sealed");
+                EXTENSION_LIST = new Name("Extension-List");
+                EXTENSION_NAME = new Name("Extension-Name");
+                EXTENSION_INSTALLATION = new Name("Extension-Installation");
+                IMPLEMENTATION_TITLE = new Name("Implementation-Title");
+                IMPLEMENTATION_VERSION = new Name("Implementation-Version");
+                IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor");
+                IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
+                IMPLEMENTATION_URL = new Name("Implementation-URL");
+                SPECIFICATION_TITLE = new Name("Specification-Title");
+                SPECIFICATION_VERSION = new Name("Specification-Version");
+                SPECIFICATION_VENDOR = new Name("Specification-Vendor");
+                // Android-removed: multi-release JARs are not supported.
+                // MULTI_RELEASE = new Name("Multi-Release");
+
+                var names = new HashMap<String, Name>(64);
+                addName(names, MANIFEST_VERSION);
+                addName(names, SIGNATURE_VERSION);
+                addName(names, CONTENT_TYPE);
+                addName(names, CLASS_PATH);
+                addName(names, MAIN_CLASS);
+                addName(names, SEALED);
+                addName(names, EXTENSION_LIST);
+                addName(names, EXTENSION_NAME);
+                addName(names, EXTENSION_INSTALLATION);
+                addName(names, IMPLEMENTATION_TITLE);
+                addName(names, IMPLEMENTATION_VERSION);
+                addName(names, IMPLEMENTATION_VENDOR);
+                addName(names, IMPLEMENTATION_VENDOR_ID);
+                addName(names, IMPLEMENTATION_URL);
+                addName(names, SPECIFICATION_TITLE);
+                addName(names, SPECIFICATION_VERSION);
+                addName(names, SPECIFICATION_VENDOR);
+                // Android-removed: multi-release JARs are not supported.
+                // addName(names, MULTI_RELEASE);
+
+                // Common attributes used in MANIFEST.MF et.al; adding these has a
+                // small footprint cost, but is likely to be quickly paid for by
+                // reducing allocation when reading and parsing typical manifests
+
+                // JDK internal attributes
+                addName(names, new Name("Add-Exports"));
+                addName(names, new Name("Add-Opens"));
+                // LauncherHelper attributes
+                addName(names, new Name("Launcher-Agent-Class"));
+                addName(names, new Name("JavaFX-Application-Class"));
+                // jarsigner attributes
+                addName(names, new Name("Name"));
+                addName(names, new Name("Created-By"));
+                addName(names, new Name("SHA1-Digest"));
+                addName(names, new Name("SHA-256-Digest"));
+                KNOWN_NAMES = Map.copyOf(names);
+            } else {
+                // Even if KNOWN_NAMES was read from archive, we still need
+                // to initialize the public constants
+                MANIFEST_VERSION = KNOWN_NAMES.get("Manifest-Version");
+                SIGNATURE_VERSION = KNOWN_NAMES.get("Signature-Version");
+                CONTENT_TYPE = KNOWN_NAMES.get("Content-Type");
+                CLASS_PATH = KNOWN_NAMES.get("Class-Path");
+                MAIN_CLASS = KNOWN_NAMES.get("Main-Class");
+                SEALED = KNOWN_NAMES.get("Sealed");
+                EXTENSION_LIST = KNOWN_NAMES.get("Extension-List");
+                EXTENSION_NAME = KNOWN_NAMES.get("Extension-Name");
+                EXTENSION_INSTALLATION = KNOWN_NAMES.get("Extension-Installation");
+                IMPLEMENTATION_TITLE = KNOWN_NAMES.get("Implementation-Title");
+                IMPLEMENTATION_VERSION = KNOWN_NAMES.get("Implementation-Version");
+                IMPLEMENTATION_VENDOR = KNOWN_NAMES.get("Implementation-Vendor");
+                IMPLEMENTATION_VENDOR_ID = KNOWN_NAMES.get("Implementation-Vendor-Id");
+                IMPLEMENTATION_URL = KNOWN_NAMES.get("Implementation-URL");
+                SPECIFICATION_TITLE = KNOWN_NAMES.get("Specification-Title");
+                SPECIFICATION_VERSION = KNOWN_NAMES.get("Specification-Version");
+                SPECIFICATION_VENDOR = KNOWN_NAMES.get("Specification-Vendor");
+                // Android-removed: multi-release JARs are not supported.
+                // MULTI_RELEASE = KNOWN_NAMES.get("Multi-Release");
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/jar/JarEntry.java b/android-35/java/util/jar/JarEntry.java
new file mode 100644
index 0000000..8402f29
--- /dev/null
+++ b/android-35/java/util/jar/JarEntry.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+
+/**
+ * This class is used to represent a JAR file entry.
+ *
+ * @since 1.2
+ */
+public
+class JarEntry extends ZipEntry {
+    Attributes attr;
+    Certificate[] certs;
+    CodeSigner[] signers;
+
+    /**
+     * Creates a new <code>JarEntry</code> for the specified JAR file
+     * entry name.
+     *
+     * @param name the JAR file entry name
+     * @exception NullPointerException if the entry name is <code>null</code>
+     * @exception IllegalArgumentException if the entry name is longer than
+     *            0xFFFF bytes.
+     */
+    public JarEntry(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>ZipEntry</code> object.
+     * @param ze the <code>ZipEntry</code> object to create the
+     *           <code>JarEntry</code> from
+     */
+    public JarEntry(ZipEntry ze) {
+        super(ze);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>JarEntry</code> object.
+     *
+     * @param je the <code>JarEntry</code> to copy
+     */
+    public JarEntry(JarEntry je) {
+        this((ZipEntry)je);
+        this.attr = je.attr;
+        this.certs = je.certs;
+        this.signers = je.signers;
+    }
+
+    /**
+     * Returns the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Attributes getAttributes() throws IOException {
+        return attr;
+    }
+
+    /**
+     * Returns the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned certificate array comprises all the signer certificates
+     * that were used to verify this entry. Each signer certificate is
+     * followed by its supporting certificate chain (which may be empty).
+     * Each signer certificate and its supporting certificate chain are ordered
+     * bottom-to-top (i.e., with the signer certificate first and the (root)
+     * certificate authority last).
+     *
+     * @return the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none.
+     */
+    public Certificate[] getCertificates() {
+        return certs == null ? null : certs.clone();
+    }
+
+    /**
+     * Returns the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned array comprises all the code signers that have signed
+     * this entry.
+     *
+     * @return the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none.
+     *
+     * @since 1.5
+     */
+    public CodeSigner[] getCodeSigners() {
+        return signers == null ? null : signers.clone();
+    }
+
+    /**
+     * This method returns the same name that {@link #getName()} returns.
+     *
+     * @return the real name of the JarEntry
+     *
+     * @since 10
+     */
+    public String getRealName() {
+        return super.getName();
+    }
+}
diff --git a/android-35/java/util/jar/JarException.java b/android-35/java/util/jar/JarException.java
new file mode 100644
index 0000000..b6e1ca2
--- /dev/null
+++ b/android-35/java/util/jar/JarException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+/**
+ * Signals that an error of some sort has occurred while reading from
+ * or writing to a JAR file.
+ *
+ * @author  David Connelly
+ * @since   1.2
+ */
+public
+class JarException extends java.util.zip.ZipException {
+    private static final long serialVersionUID = 7159778400963954473L;
+
+    /**
+     * Constructs a JarException with no detail message.
+     */
+    public JarException() {
+    }
+
+    /**
+     * Constructs a JarException with the specified detail message.
+     * @param s the detail message
+     */
+    public JarException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/jar/JarFile.java b/android-35/java/util/jar/JarFile.java
new file mode 100644
index 0000000..1d29e1c
--- /dev/null
+++ b/android-35/java/util/jar/JarFile.java
@@ -0,0 +1,922 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.lang.ref.SoftReference;
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import java.util.zip.*;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+import java.security.AccessController;
+import sun.misc.IOUtils;
+import sun.security.action.GetPropertyAction;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+
+/**
+ * The <code>JarFile</code> class is used to read the contents of a jar file
+ * from any file that can be opened with <code>java.io.RandomAccessFile</code>.
+ * It extends the class <code>java.util.zip.ZipFile</code> with support
+ * for reading an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about the
+ * jar file and its entries.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * If the verify flag is on when opening a signed jar file, the content of the
+ * file is verified against its signature embedded inside the file. Please note
+ * that the verification process does not include validating the signer's
+ * certificate. A caller should inspect the return value of
+ * {@link JarEntry#getCodeSigners()} to further determine if the signature
+ * can be trusted.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipFile
+ * @see     java.util.jar.JarEntry
+ * @since   1.2
+ */
+public
+class JarFile extends ZipFile {
+    // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+    // private SoftReference<Manifest> manRef;
+    private Manifest manifest;
+    private JarEntry manEntry;
+    private JarVerifier jv;
+    private boolean jvInitialized;
+    private boolean verify;
+
+    // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true)
+    private boolean hasClassPathAttribute;
+    // true if manifest checked for special attributes
+    private volatile boolean hasCheckedSpecialAttributes;
+
+    // Android-removed: SharedSecrets.setJavaUtilJarAccess
+    /*
+    // Set up JavaUtilJarAccess in SharedSecrets
+    static {
+        SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
+    }
+    */
+
+    /**
+     * The JAR manifest file name.
+     */
+    public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param name the name of the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name) throws IOException {
+        this(new File(name), true, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>.
+     * @param name the name of the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name, boolean verify) throws IOException {
+        this(new File(name), verify, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param file the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(File file) throws IOException {
+        this(file, true, ZipFile.OPEN_READ);
+    }
+
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object.
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager.
+     */
+    public JarFile(File file, boolean verify) throws IOException {
+        this(file, verify, ZipFile.OPEN_READ);
+    }
+
+
+    // Android-changed: Use of the hidden constructor with a new argument for zip path validation.
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @param mode the mode in which the file is to be opened
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalArgumentException
+     *         if the <tt>mode</tt> argument is invalid
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     * @since 1.3
+     */
+    public JarFile(File file, boolean verify, int mode) throws IOException {
+        this(file, /* enableZipPathValidator */ true, verify, mode);
+    }
+
+    // Android-added: New hidden constructor with an argument for zip path validation and verify.
+    /** @hide */
+    public JarFile(String name, boolean enableZipPathValidator, boolean verify) throws IOException {
+        this(new File(name), enableZipPathValidator, verify, ZipFile.OPEN_READ);
+    }
+
+    // Android-added: New hidden constructor with all available arguments.
+    /** @hide */
+    public JarFile(File file, boolean enableZipPathValidator, boolean verify, int mode) throws
+            IOException {
+        super(file, mode, enableZipPathValidator);
+        this.verify = verify;
+    }
+
+    /**
+     * Returns the jar file manifest, or <code>null</code> if none.
+     *
+     * @return the jar file manifest, or <code>null</code> if none
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Manifest getManifest() throws IOException {
+        return getManifestFromReference();
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private Manifest getManifestFromReference() throws IOException {
+    private synchronized Manifest getManifestFromReference() throws IOException {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+        // Manifest man = manRef != null ? manRef.get() : null;
+        Manifest man = manifest;
+        if (man == null) {
+
+            JarEntry manEntry = getManEntry();
+
+            // If found then load the manifest
+            if (manEntry != null) {
+                if (verify) {
+                    byte[] b = getBytes(manEntry);
+                    man = new Manifest(new ByteArrayInputStream(b));
+                    if (!jvInitialized) {
+                        jv = new JarVerifier(manEntry.getName(), b);
+                    }
+                } else {
+                    man = new Manifest(super.getInputStream(manEntry));
+                }
+                // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+                // manRef = new SoftReference<>(man);
+                manifest = man;
+            }
+        }
+        return man;
+    }
+
+    private native String[] getMetaInfEntryNames();
+
+    /**
+     * Returns the <code>JarEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>JarEntry</code> for the given entry name or
+     *         <code>null</code> if not found.
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.jar.JarEntry
+     */
+    public JarEntry getJarEntry(String name) {
+        return (JarEntry)getEntry(name);
+    }
+
+    /**
+     * Returns the <code>ZipEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>ZipEntry</code> for the given entry name or
+     *         <code>null</code> if not found
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.zip.ZipEntry
+     */
+    public ZipEntry getEntry(String name) {
+        ZipEntry ze = super.getEntry(name);
+        if (ze != null) {
+            return new JarFileEntry(ze);
+        }
+        return null;
+    }
+
+    private class JarEntryIterator implements Enumeration<JarEntry>,
+            Iterator<JarEntry>
+    {
+        final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
+
+        public boolean hasNext() {
+            return e.hasMoreElements();
+        }
+
+        public JarEntry next() {
+            ZipEntry ze = e.nextElement();
+            return new JarFileEntry(ze);
+        }
+
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        public JarEntry nextElement() {
+            return next();
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries.
+     */
+    public Enumeration<JarEntry> entries() {
+        return new JarEntryIterator();
+    }
+
+    @Override
+    public Stream<JarEntry> stream() {
+        return StreamSupport.stream(Spliterators.spliterator(
+                new JarEntryIterator(), size(),
+                Spliterator.ORDERED | Spliterator.DISTINCT |
+                        Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    // Android-added: this method is from OpenJDK 17. Made public hidden to access it
+    // in ZipFile w/o SharedSecrets.
+    /**
+     * Creates a ZipEntry suitable for the given ZipFile.
+     * @hide
+     */
+    public JarEntry entryFor(String name) {
+        return new JarFileEntry(name);
+    }
+
+    private class JarFileEntry extends JarEntry {
+        JarFileEntry(ZipEntry ze) {
+            super(ze);
+        }
+
+        // Android-added: imported from OpenJDK 17 for entryFor(String) support.
+        JarFileEntry(String name) {
+            super(name);
+        }
+
+        public Attributes getAttributes() throws IOException {
+            Manifest man = JarFile.this.getManifest();
+            if (man != null) {
+                return man.getAttributes(getName());
+            } else {
+                return null;
+            }
+        }
+        public Certificate[] getCertificates() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (certs == null && jv != null) {
+                certs = jv.getCerts(JarFile.this, this);
+            }
+            return certs == null ? null : certs.clone();
+        }
+        public CodeSigner[] getCodeSigners() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (signers == null && jv != null) {
+                signers = jv.getCodeSigners(JarFile.this, this);
+            }
+            return signers == null ? null : signers.clone();
+        }
+    }
+
+    /*
+     * Ensures that the JarVerifier has been created if one is
+     * necessary (i.e., the jar appears to be signed.) This is done as
+     * a quick check to avoid processing of the manifest for unsigned
+     * jars.
+     */
+    private void maybeInstantiateVerifier() throws IOException {
+        if (jv != null) {
+            return;
+        }
+
+        if (verify) {
+            // BEGIN Android-changed: use OpenJDK 17 implementation.
+            /*
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String name = names[i].toUpperCase(Locale.ENGLISH);
+                    if (name.endsWith(".DSA") ||
+                        name.endsWith(".RSA") ||
+                        name.endsWith(".EC") ||
+                        name.endsWith(".SF")) {
+                        // Assume since we found a signature-related file
+                        // that the jar is signed and that we therefore
+                        // need a JarVerifier and Manifest
+                        getManifest();
+                        return;
+                    }
+                }
+            }
+            // No signature-related files; don't instantiate a
+            // verifier
+            verify = false;
+            */
+            // Gets the manifest name, but only if there are
+            // signature-related files. If so we can assume
+            // that the jar is signed and that we therefore
+            // need a JarVerifier and Manifest
+            // String name = JUZFA.getManifestName(this, true);
+            String name = getManifestName(true);
+            if (name != null) {
+                getManifest();
+                return;
+            }
+            // No signature-related files; don't instantiate a
+            // verifier
+            verify = false;
+            // END Android-changed: use OpenJDK 17 implementation.
+        }
+    }
+
+
+    /*
+     * Initializes the verifier object by reading all the manifest
+     * entries and passing them to the verifier.
+     */
+    private void initializeVerifier() {
+        ManifestEntryVerifier mev = null;
+
+        // Verify "META-INF/" entries...
+        // BEGIN Android-changed: use OpenJDK17 implementation.
+        /*
+        try {
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String uname = names[i].toUpperCase(Locale.ENGLISH);
+                    if (MANIFEST_NAME.equals(uname)
+                            || SignatureFileVerifier.isBlockOrSF(uname)) {
+                        JarEntry e = getJarEntry(names[i]);
+                        if (e == null) {
+                            throw new JarException("corrupted jar file");
+                        }
+                        if (mev == null) {
+                            mev = new ManifestEntryVerifier
+                                (getManifestFromReference());
+                        }
+                        byte[] b = getBytes(e);
+                        if (b != null && b.length > 0) {
+                            jv.beginEntry(e, mev);
+                            jv.update(b.length, b, 0, b.length, mev);
+                            jv.update(-1, null, 0, 0, mev);
+                        }
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            // if we had an error parsing any blocks, just
+            // treat the jar file as being unsigned
+            jv = null;
+            verify = false;
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("jarfile parsing error!");
+                ex.printStackTrace();
+            }
+        }
+        */
+        try {
+            List<String> names = getManifestAndSignatureRelatedFiles();
+            for (String name : names) {
+                JarEntry e = getJarEntry(name);
+                byte[] b;
+                if (e == null) {
+                    throw new JarException("corrupted jar file");
+                }
+                if (mev == null) {
+                    // BEGIN Android-changed: ManifestEntryVerifier(Manifest, String) is not imported yet.
+                    /*
+                    mev = new ManifestEntryVerifier
+                            (getManifestFromReference()), jv.manifestName);
+                    */
+                    mev = new ManifestEntryVerifier(getManifestFromReference());
+                    // END Android-changed: ManifestEntryVerifier(Manifest, String) is not imported yet.
+                }
+                if (name.equalsIgnoreCase(MANIFEST_NAME)) {
+                    b = jv.manifestRawBytes;
+                } else {
+                    b = getBytes(e);
+                }
+                if (b != null && b.length > 0) {
+                    jv.beginEntry(e, mev);
+                    jv.update(b.length, b, 0, b.length, mev);
+                    jv.update(-1, null, 0, 0, mev);
+                }
+            }
+        } catch (IOException | IllegalArgumentException ex) {
+            // if we had an error parsing any blocks, just
+            // treat the jar file as being unsigned
+            jv = null;
+            verify = false;
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("jarfile parsing error!");
+                ex.printStackTrace();
+            }
+        }
+        // END Android-changed: use OpenJDK17 implementation.
+
+        // if after initializing the verifier we have nothing
+        // signed, we null it out.
+
+        if (jv != null) {
+
+            jv.doneWithMeta();
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("done with meta!");
+            }
+
+            if (jv.nothingToVerify()) {
+                if (JarVerifier.debug != null) {
+                    JarVerifier.debug.println("nothing to verify!");
+                }
+                jv = null;
+                verify = false;
+            }
+        }
+    }
+
+    /*
+     * Reads all the bytes for a given entry. Used to process the
+     * META-INF files.
+     */
+    private byte[] getBytes(ZipEntry ze) throws IOException {
+        try (InputStream is = super.getInputStream(ze)) {
+            return IOUtils.readFully(is, (int)ze.getSize(), true);
+        }
+    }
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     * @param ze the zip file entry
+     * @return an input stream for reading the contents of the specified
+     *         zip file entry
+     * @throws ZipException if a zip file format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     */
+    public synchronized InputStream getInputStream(ZipEntry ze)
+        throws IOException
+    {
+        maybeInstantiateVerifier();
+        if (jv == null) {
+            return super.getInputStream(ze);
+        }
+        if (!jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+            // could be set to null after a call to
+            // initializeVerifier if we have nothing to
+            // verify
+            if (jv == null)
+                return super.getInputStream(ze);
+        }
+
+        // wrap a verifier stream around the real stream
+        return new JarVerifier.VerifierStream(
+            getManifestFromReference(),
+            ze instanceof JarFileEntry ?
+                    (JarEntry) ze : getJarEntry(ze.getName()),
+            super.getInputStream(ze),
+            jv);
+    }
+
+    // Statics for hand-coded Boyer-Moore search
+    private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'};
+    // The bad character shift for "class-path"
+    private static final int[] CLASSPATH_LASTOCC;
+    // The good suffix shift for "class-path"
+    private static final int[] CLASSPATH_OPTOSFT;
+
+    static {
+        CLASSPATH_LASTOCC = new int[128];
+        CLASSPATH_OPTOSFT = new int[10];
+        CLASSPATH_LASTOCC[(int)'c'] = 1;
+        CLASSPATH_LASTOCC[(int)'l'] = 2;
+        CLASSPATH_LASTOCC[(int)'s'] = 5;
+        CLASSPATH_LASTOCC[(int)'-'] = 6;
+        CLASSPATH_LASTOCC[(int)'p'] = 7;
+        CLASSPATH_LASTOCC[(int)'a'] = 8;
+        CLASSPATH_LASTOCC[(int)'t'] = 9;
+        CLASSPATH_LASTOCC[(int)'h'] = 10;
+        for (int i=0; i<9; i++)
+            CLASSPATH_OPTOSFT[i] = 10;
+        CLASSPATH_OPTOSFT[9]=1;
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private JarEntry getManEntry() {
+    private synchronized JarEntry getManEntry() {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        // BEGIN Android-changed: use OpenJDK 17 implementation.
+        /*
+        if (manEntry == null) {
+            // First look up manifest entry using standard name
+            manEntry = getJarEntry(MANIFEST_NAME);
+            if (manEntry == null) {
+                // If not found, then iterate through all the "META-INF/"
+                // entries to find a match.
+                String[] names = getMetaInfEntryNames();
+                if (names != null) {
+                    for (int i = 0; i < names.length; i++) {
+                        if (MANIFEST_NAME.equals(
+                                                 names[i].toUpperCase(Locale.ENGLISH))) {
+                            manEntry = getJarEntry(names[i]);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        */
+        if (manEntry == null) {
+            // The manifest entry position is resolved during
+            // initialization
+            String name = getManifestName(false);
+            if (name != null) {
+                this.manEntry = (JarEntry)super.getEntry(name);
+            }
+        }
+        // END Android-changed: use OpenJDK 17 implementation.
+        return manEntry;
+    }
+
+    /**
+     * Returns {@code true} iff this JAR file has a manifest with the
+     * Class-Path attribute
+     * @hide
+     */
+    // Android-changed: Make hasClassPathAttribute() @hide public, for internal use.
+    // Used by URLClassPath.JarLoader.
+    // boolean hasClassPathAttribute() throws IOException {
+    public boolean hasClassPathAttribute() throws IOException {
+        checkForSpecialAttributes();
+        return hasClassPathAttribute;
+    }
+
+    /**
+     * Returns true if the pattern {@code src} is found in {@code b}.
+     * The {@code lastOcc} and {@code optoSft} arrays are the precomputed
+     * bad character and good suffix shifts.
+     */
+    private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) {
+        int len = src.length;
+        int last = b.length - len;
+        int i = 0;
+        next:
+        while (i<=last) {
+            for (int j=(len-1); j>=0; j--) {
+                char c = (char) b[i+j];
+                c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c;
+                if (c != src[j]) {
+                    i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]);
+                    continue next;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * On first invocation, check if the JAR file has the Class-Path
+     * attribute. A no-op on subsequent calls.
+     */
+    private void checkForSpecialAttributes() throws IOException {
+        if (hasCheckedSpecialAttributes) return;
+        // Android-changed: Special handling of well-known .jar files specific to OpenJDK.
+        // if (!isKnownNotToHaveSpecialAttributes()) {
+        {
+            JarEntry manEntry = getManEntry();
+            if (manEntry != null) {
+                byte[] b = getBytes(manEntry);
+                if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT))
+                    hasClassPathAttribute = true;
+            }
+        }
+        hasCheckedSpecialAttributes = true;
+    }
+
+
+    // Android-removed: Special handling of well-known .jar files specific to OpenJDK.
+    /*
+    private static String javaHome;
+    private static volatile String[] jarNames;
+    private boolean isKnownNotToHaveSpecialAttributes() {
+        // Optimize away even scanning of manifest for jar files we
+        // deliver which don't have a class-path attribute. If one of
+        // these jars is changed to include such an attribute this code
+        // must be changed.
+        if (javaHome == null) {
+            javaHome = AccessController.doPrivileged(
+                new GetPropertyAction("java.home"));
+        }
+        if (jarNames == null) {
+            String[] names = new String[11];
+            String fileSep = File.separator;
+            int i = 0;
+            names[i++] = fileSep + "rt.jar";
+            names[i++] = fileSep + "jsse.jar";
+            names[i++] = fileSep + "jce.jar";
+            names[i++] = fileSep + "charsets.jar";
+            names[i++] = fileSep + "dnsns.jar";
+            names[i++] = fileSep + "zipfs.jar";
+            names[i++] = fileSep + "localedata.jar";
+            names[i++] = fileSep = "cldrdata.jar";
+            names[i++] = fileSep + "sunjce_provider.jar";
+            names[i++] = fileSep + "sunpkcs11.jar";
+            names[i++] = fileSep + "sunec.jar";
+            jarNames = names;
+        }
+
+        String name = getName();
+        String localJavaHome = javaHome;
+        if (name.startsWith(localJavaHome)) {
+            String[] names = jarNames;
+            for (int i = 0; i < names.length; i++) {
+                if (name.endsWith(names[i])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    */
+
+    // Android-removed: Unused method ensureInitialization().
+    /*
+    private synchronized void ensureInitialization() {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null && !jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+        }
+    }
+    */
+
+    JarEntry newEntry(ZipEntry ze) {
+        return new JarFileEntry(ze);
+    }
+
+    // Android-removed: Unused methods entryNames(), entries2().
+    /*
+    Enumeration<String> entryNames(CodeSource[] cs) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entryNames(this, cs);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        boolean includeUnsigned = false;
+        for (int i = 0; i < cs.length; i++) {
+            if (cs[i].getCodeSigners() == null) {
+                includeUnsigned = true;
+                break;
+            }
+        }
+        if (includeUnsigned) {
+            return unsignedEntryNames();
+        } else {
+            return new Enumeration<String>() {
+
+                public boolean hasMoreElements() {
+                    return false;
+                }
+
+                public String nextElement() {
+                    throw new NoSuchElementException();
+                }
+            };
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries
+     * excluding internal JAR mechanism entries and including
+     * signed entries missing from the ZIP directory.
+     *
+    Enumeration<JarEntry> entries2() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entries2(this, super.entries());
+        }
+
+        // screen out entries which are never signed
+        final Enumeration<? extends ZipEntry> enum_ = super.entries();
+        return new Enumeration<JarEntry>() {
+
+            ZipEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = ze;
+                    return true;
+                }
+                return false;
+            }
+
+            public JarFileEntry nextElement() {
+                if (hasMoreElements()) {
+                    ZipEntry ze = entry;
+                    entry = null;
+                    return new JarFileEntry(ze);
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource[] getCodeSources(URL url) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getCodeSources(this, url);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        Enumeration<String> unsigned = unsignedEntryNames();
+        if (unsigned.hasMoreElements()) {
+            return new CodeSource[]{JarVerifier.getUnsignedCS(url)};
+        } else {
+            return null;
+        }
+    }
+
+    private Enumeration<String> unsignedEntryNames() {
+        final Enumeration<JarEntry> entries = entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             *
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || JarVerifier.isSigningRelated(value)) {
+                        continue;
+                    }
+                    name = value;
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource getCodeSource(URL url, String name) {
+        ensureInitialization();
+        if (jv != null) {
+            if (jv.eagerValidation) {
+                CodeSource cs = null;
+                JarEntry je = getJarEntry(name);
+                if (je != null) {
+                    cs = jv.getCodeSource(url, this, je);
+                } else {
+                    cs = jv.getCodeSource(url, name);
+                }
+                return cs;
+            } else {
+                return jv.getCodeSource(url, name);
+            }
+        }
+
+        return JarVerifier.getUnsignedCS(url);
+    }
+
+    void setEagerValidation(boolean eager) {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null) {
+            jv.setEagerValidation(eager);
+        }
+    }
+
+    List<Object> getManifestDigests() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getManifestDigests();
+        }
+        return new ArrayList<Object>();
+    }
+    */
+}
diff --git a/android-35/java/util/jar/JarInputStream.java b/android-35/java/util/jar/JarInputStream.java
new file mode 100644
index 0000000..adcd63e
--- /dev/null
+++ b/android-35/java/util/jar/JarInputStream.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+import sun.security.util.ManifestEntryVerifier;
+import jdk.internal.util.jar.JarIndex;
+
+/**
+ * The <code>JarInputStream</code> class is used to read the contents of
+ * a JAR file from any input stream. It extends the class
+ * <code>java.util.zip.ZipInputStream</code> with support for reading
+ * an optional <code>Manifest</code> entry. The <code>Manifest</code>
+ * can be used to store meta-information about the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipInputStream
+ * @since   1.2
+ */
+public
+class JarInputStream extends ZipInputStream {
+    private Manifest man;
+    private JarEntry first;
+    private JarVerifier jv;
+    private ManifestEntryVerifier mev;
+    private final boolean doVerify;
+    private boolean tryManifest;
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present, also attempts to verify
+     * the signatures if the JarInputStream is signed.
+     * @param in the actual input stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in) throws IOException {
+        this(in, true);
+    }
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present and verify is true, also attempts
+     * to verify the signatures if the JarInputStream is signed.
+     *
+     * @param in the actual input stream
+     * @param verify whether or not to verify the JarInputStream if
+     * it is signed.
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in, boolean verify) throws IOException {
+        super(in);
+        this.doVerify = verify;
+
+        // This implementation assumes the META-INF/MANIFEST.MF entry
+        // should be either the first or the second entry (when preceded
+        // by the dir META-INF/). It skips the META-INF/ and then
+        // "consumes" the MANIFEST.MF to initialize the Manifest object.
+        JarEntry e = (JarEntry)super.getNextEntry();
+        if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
+            e = (JarEntry)super.getNextEntry();
+        first = checkManifest(e);
+    }
+
+    private JarEntry checkManifest(JarEntry e)
+        throws IOException
+    {
+        if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
+            man = new Manifest();
+            byte bytes[] = getBytes(new BufferedInputStream(this));
+            man.read(new ByteArrayInputStream(bytes));
+            closeEntry();
+            if (doVerify) {
+                jv = new JarVerifier(e.getName(), bytes);
+                mev = new ManifestEntryVerifier(man);
+            }
+            return (JarEntry)super.getNextEntry();
+        }
+        return e;
+    }
+
+    private byte[] getBytes(InputStream is)
+        throws IOException
+    {
+        byte[] buffer = new byte[8192];
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
+        int n;
+        while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+            baos.write(buffer, 0, n);
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Returns the <code>Manifest</code> for this JAR file, or
+     * <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> for this JAR file, or
+     *         <code>null</code> if none.
+     */
+    public Manifest getManifest() {
+        return man;
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        JarEntry e;
+        if (first == null) {
+            e = (JarEntry)super.getNextEntry();
+            if (tryManifest) {
+                e = checkManifest(e);
+                tryManifest = false;
+            }
+        } else {
+            e = first;
+            if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
+                tryManifest = true;
+            first = null;
+        }
+        if (jv != null && e != null) {
+            // At this point, we might have parsed all the meta-inf
+            // entries and have nothing to verify. If we have
+            // nothing to verify, get rid of the JarVerifier object.
+            if (jv.nothingToVerify() == true) {
+                jv = null;
+                mev = null;
+            } else {
+                jv.beginEntry(e, mev);
+            }
+        }
+        return e;
+    }
+
+    /**
+     * Reads the next JAR file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @return the next JAR file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public JarEntry getNextJarEntry() throws IOException {
+        return (JarEntry)getNextEntry();
+    }
+
+    /**
+     * Reads from the current JAR file entry into an array of bytes.
+     * If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * If verification has been enabled, any invalid signature
+     * on the current entry will be reported at some point before the
+     * end of the entry is reached.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes to read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        int n;
+        if (first == null) {
+            n = super.read(b, off, len);
+        } else {
+            n = -1;
+        }
+        if (jv != null) {
+            jv.update(n, b, off, len, mev);
+        }
+        return n;
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
+     * specified JAR file entry name. The manifest attributes of
+     * the specified JAR file entry name will be copied to the new
+     * <CODE>JarEntry</CODE>.
+     *
+     * @param name the name of the JAR/ZIP file entry
+     * @return the <code>JarEntry</code> object just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        JarEntry e = new JarEntry(name);
+        if (man != null) {
+            e.attr = man.getAttributes(name);
+        }
+        return e;
+    }
+}
diff --git a/android-35/java/util/jar/JarOutputStream.java b/android-35/java/util/jar/JarOutputStream.java
new file mode 100644
index 0000000..3694277
--- /dev/null
+++ b/android-35/java/util/jar/JarOutputStream.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+
+/**
+ * The <code>JarOutputStream</code> class is used to write the contents
+ * of a JAR file to any output stream. It extends the class
+ * <code>java.util.zip.ZipOutputStream</code> with support
+ * for writing an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about
+ * the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipOutputStream
+ * @since   1.2
+ */
+public
+class JarOutputStream extends ZipOutputStream {
+    private static final int JAR_MAGIC = 0xCAFE;
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with the specified
+     * <code>Manifest</code>. The manifest is written as the first
+     * entry to the output stream.
+     *
+     * @param out the actual output stream
+     * @param man the optional <code>Manifest</code>
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out, Manifest man) throws IOException {
+        super(out);
+        if (man == null) {
+            throw new NullPointerException("man");
+        }
+        ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+        putNextEntry(e);
+        man.write(new BufferedOutputStream(this));
+        closeEntry();
+    }
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with no manifest.
+     * @param out the actual output stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out) throws IOException {
+        super(out);
+    }
+
+    /**
+     * Begins writing a new JAR file entry and positions the stream
+     * to the start of the entry data. This method will also close
+     * any previous entry. The default compression method will be
+     * used if no compression method was specified for the entry.
+     * The current time will be used if the entry has no set modification
+     * time.
+     *
+     * @param ze the ZIP/JAR entry to be written
+     * @exception ZipException if a ZIP error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry ze) throws IOException {
+        if (firstEntry) {
+            // Make sure that extra field data for first JAR
+            // entry includes JAR magic number id.
+            byte[] edata = ze.getExtra();
+            if (edata == null || !hasMagic(edata)) {
+                if (edata == null) {
+                    edata = new byte[4];
+                } else {
+                    // Prepend magic to existing extra data
+                    byte[] tmp = new byte[edata.length + 4];
+                    System.arraycopy(edata, 0, tmp, 4, edata.length);
+                    edata = tmp;
+                }
+                set16(edata, 0, JAR_MAGIC); // extra field id
+                set16(edata, 2, 0);         // extra field size
+                ze.setExtra(edata);
+            }
+            firstEntry = false;
+        }
+        super.putNextEntry(ze);
+    }
+
+    private boolean firstEntry = true;
+
+    /*
+     * Returns true if specified byte array contains the
+     * jar magic extra field id.
+     */
+    private static boolean hasMagic(byte[] edata) {
+        try {
+            int i = 0;
+            while (i < edata.length) {
+                if (get16(edata, i) == JAR_MAGIC) {
+                    return true;
+                }
+                i += get16(edata, i + 2) + 4;
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Invalid extra field data
+        }
+        return false;
+    }
+
+    /*
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    private static int get16(byte[] b, int off) {
+        return Byte.toUnsignedInt(b[off]) | ( Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /*
+     * Sets 16-bit value at specified offset. The bytes are assumed to
+     * be in Intel (little-endian) byte order.
+     */
+    private static void set16(byte[] b, int off, int value) {
+        b[off+0] = (byte)value;
+        b[off+1] = (byte)(value >> 8);
+    }
+}
diff --git a/android-35/java/util/jar/JarVerifier.java b/android-35/java/util/jar/JarVerifier.java
new file mode 100644
index 0000000..637471f
--- /dev/null
+++ b/android-35/java/util/jar/JarVerifier.java
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.util.zip.ZipEntry;
+
+import jdk.internal.util.jar.JarIndex;
+import sun.security.util.ManifestDigester;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+import sun.security.util.Debug;
+
+/**
+ *
+ * @author      Roland Schemers
+ */
+class JarVerifier {
+
+    /* Are we debugging ? */
+    static final Debug debug = Debug.getInstance("jar");
+
+    /* a table mapping names to code signers, for jar entries that have
+       had their actual hashes verified */
+    private Hashtable<String, CodeSigner[]> verifiedSigners;
+
+    /* a table mapping names to code signers, for jar entries that have
+       passed the .SF/.DSA/.EC -> MANIFEST check */
+    private Hashtable<String, CodeSigner[]> sigFileSigners;
+
+    /* a hash table to hold .SF bytes */
+    private Hashtable<String, byte[]> sigFileData;
+
+    /** "queue" of pending PKCS7 blocks that we couldn't parse
+     *  until we parsed the .SF file */
+    private ArrayList<SignatureFileVerifier> pendingBlocks;
+
+    /* cache of CodeSigner objects */
+    private ArrayList<CodeSigner[]> signerCache;
+
+    /* Are we parsing a block? */
+    private boolean parsingBlockOrSF = false;
+
+    /* Are we done parsing META-INF entries? */
+    private boolean parsingMeta = true;
+
+    /* Are there are files to verify? */
+    private boolean anyToVerify = true;
+
+    /* The output stream to use when keeping track of files we are interested
+       in */
+    private ByteArrayOutputStream baos;
+
+    /** The ManifestDigester object */
+    private volatile ManifestDigester manDig;
+
+    /** the bytes for the manDig object */
+    byte manifestRawBytes[] = null;
+
+    /** the manifest name this JarVerifier is created upon */
+    final String manifestName;
+
+    /** controls eager signature validation */
+    boolean eagerValidation;
+
+    /** makes code source singleton instances unique to us */
+    private Object csdomain = new Object();
+
+    /** collect -DIGEST-MANIFEST values for blacklist */
+    private List<Object> manifestDigests;
+
+    public JarVerifier(String name, byte rawBytes[]) {
+        manifestName = name;
+        manifestRawBytes = rawBytes;
+        sigFileSigners = new Hashtable<>();
+        verifiedSigners = new Hashtable<>();
+        sigFileData = new Hashtable<>(11);
+        pendingBlocks = new ArrayList<>();
+        baos = new ByteArrayOutputStream();
+        manifestDigests = new ArrayList<>();
+    }
+
+    /**
+     * This method scans to see which entry we're parsing and
+     * keeps various state information depending on what type of
+     * file is being parsed.
+     */
+    public void beginEntry(JarEntry je, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (je == null)
+            return;
+
+        if (debug != null) {
+            debug.println("beginEntry "+je.getName());
+        }
+
+        String name = je.getName();
+
+        /*
+         * Assumptions:
+         * 1. The manifest should be the first entry in the META-INF directory.
+         * 2. The .SF/.DSA/.EC files follow the manifest, before any normal entries
+         * 3. Any of the following will throw a SecurityException:
+         *    a. digest mismatch between a manifest section and
+         *       the SF section.
+         *    b. digest mismatch between the actual jar entry and the manifest
+         */
+
+        if (parsingMeta) {
+            String uname = name.toUpperCase(Locale.ENGLISH);
+            if ((uname.startsWith("META-INF/") ||
+                 uname.startsWith("/META-INF/"))) {
+
+                if (je.isDirectory()) {
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                if (uname.equals(JarFile.MANIFEST_NAME) ||
+                        uname.equals(JarIndex.INDEX_NAME)) {
+                    return;
+                }
+
+                if (SignatureFileVerifier.isBlockOrSF(uname)) {
+                    /* We parse only DSA, RSA or EC PKCS7 blocks. */
+                    parsingBlockOrSF = true;
+                    baos.reset();
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                // If a META-INF entry is not MF or block or SF, they should
+                // be normal entries. According to 2 above, no more block or
+                // SF will appear. Let's doneWithMeta.
+            }
+        }
+
+        if (parsingMeta) {
+            doneWithMeta();
+        }
+
+        if (je.isDirectory()) {
+            mev.setEntry(null, je);
+            return;
+        }
+
+        // be liberal in what you accept. If the name starts with ./, remove
+        // it as we internally canonicalize it with out the ./.
+        if (name.startsWith("./"))
+            name = name.substring(2);
+
+        // be liberal in what you accept. If the name starts with /, remove
+        // it as we internally canonicalize it with out the /.
+        if (name.startsWith("/"))
+            name = name.substring(1);
+
+        // only set the jev object for entries that have a signature
+        // (either verified or not)
+        if (sigFileSigners.get(name) != null ||
+                verifiedSigners.get(name) != null) {
+            mev.setEntry(name, je);
+            return;
+        }
+
+        // don't compute the digest for this entry
+        mev.setEntry(null, je);
+
+        return;
+    }
+
+    /**
+     * update a single byte.
+     */
+
+    public void update(int b, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (b != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b);
+            } else {
+                mev.update((byte)b);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * update an array of bytes.
+     */
+
+    public void update(int n, byte[] b, int off, int len,
+                       ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (n != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b, off, n);
+            } else {
+                mev.update(b, off, n);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * called when we reach the end of entry in one of the read() methods.
+     */
+    private void processEntry(ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (!parsingBlockOrSF) {
+            JarEntry je = mev.getEntry();
+            if ((je != null) && (je.signers == null)) {
+                je.signers = mev.verify(verifiedSigners, sigFileSigners);
+                je.certs = mapSignersToCertArray(je.signers);
+            }
+        } else {
+
+            try {
+                parsingBlockOrSF = false;
+
+                if (debug != null) {
+                    debug.println("processEntry: processing block");
+                }
+
+                String uname = mev.getEntry().getName()
+                                             .toUpperCase(Locale.ENGLISH);
+
+                if (uname.endsWith(".SF")) {
+                    String key = uname.substring(0, uname.length()-3);
+                    byte bytes[] = baos.toByteArray();
+                    // add to sigFileData in case future blocks need it
+                    sigFileData.put(key, bytes);
+                    // check pending blocks, we can now process
+                    // anyone waiting for this .SF file
+                    Iterator<SignatureFileVerifier> it = pendingBlocks.iterator();
+                    while (it.hasNext()) {
+                        SignatureFileVerifier sfv = it.next();
+                        if (sfv.needSignatureFile(key)) {
+                            if (debug != null) {
+                                debug.println(
+                                 "processEntry: processing pending block");
+                            }
+
+                            sfv.setSignatureFile(bytes);
+                            sfv.process(sigFileSigners, manifestDigests);
+                        }
+                    }
+                    return;
+                }
+
+                // now we are parsing a signature block file
+
+                String key = uname.substring(0, uname.lastIndexOf("."));
+
+                if (signerCache == null)
+                    signerCache = new ArrayList<>();
+
+                if (manDig == null) {
+                    synchronized(manifestRawBytes) {
+                        if (manDig == null) {
+                            manDig = new ManifestDigester(manifestRawBytes);
+                            manifestRawBytes = null;
+                        }
+                    }
+                }
+
+                SignatureFileVerifier sfv =
+                  new SignatureFileVerifier(signerCache,
+                                            manDig, uname, baos.toByteArray());
+
+                if (sfv.needSignatureFileBytes()) {
+                    // see if we have already parsed an external .SF file
+                    byte[] bytes = sigFileData.get(key);
+
+                    if (bytes == null) {
+                        // put this block on queue for later processing
+                        // since we don't have the .SF bytes yet
+                        // (uname, block);
+                        if (debug != null) {
+                            debug.println("adding pending block");
+                        }
+                        pendingBlocks.add(sfv);
+                        return;
+                    } else {
+                        sfv.setSignatureFile(bytes);
+                    }
+                }
+                sfv.process(sigFileSigners, manifestDigests);
+
+            } catch (IOException ioe) {
+                // e.g. sun.security.pkcs.ParsingException
+                if (debug != null) debug.println("processEntry caught: "+ioe);
+                // ignore and treat as unsigned
+            } catch (SignatureException se) {
+                if (debug != null) debug.println("processEntry caught: "+se);
+                // ignore and treat as unsigned
+            } catch (NoSuchAlgorithmException nsae) {
+                if (debug != null) debug.println("processEntry caught: "+nsae);
+                // ignore and treat as unsigned
+            } catch (CertificateException ce) {
+                if (debug != null) debug.println("processEntry caught: "+ce);
+                // ignore and treat as unsigned
+            }
+        }
+    }
+
+    // Android-changed: @deprecated tag needs a description. http://b/110781661
+    /**
+     * Return an array of java.security.cert.Certificate objects for
+     * the given file in the jar.
+     * @deprecated Deprecated.
+     */
+    @Deprecated
+    public java.security.cert.Certificate[] getCerts(String name)
+    {
+        return mapSignersToCertArray(getCodeSigners(name));
+    }
+
+    public java.security.cert.Certificate[] getCerts(JarFile jar, JarEntry entry)
+    {
+        return mapSignersToCertArray(getCodeSigners(jar, entry));
+    }
+
+    /**
+     * return an array of CodeSigner objects for
+     * the given file in the jar. this array is not cloned.
+     *
+     */
+    public CodeSigner[] getCodeSigners(String name)
+    {
+        return verifiedSigners.get(name);
+    }
+
+    public CodeSigner[] getCodeSigners(JarFile jar, JarEntry entry)
+    {
+        String name = entry.getName();
+        if (eagerValidation && sigFileSigners.get(name) != null) {
+            /*
+             * Force a read of the entry data to generate the
+             * verification hash.
+             */
+            try {
+                InputStream s = jar.getInputStream(entry);
+                byte[] buffer = new byte[1024];
+                int n = buffer.length;
+                while (n != -1) {
+                    n = s.read(buffer, 0, buffer.length);
+                }
+                s.close();
+            } catch (IOException e) {
+            }
+        }
+        return getCodeSigners(name);
+    }
+
+    /*
+     * Convert an array of signers into an array of concatenated certificate
+     * arrays.
+     */
+    private static java.security.cert.Certificate[] mapSignersToCertArray(
+        CodeSigner[] signers) {
+
+        if (signers != null) {
+            ArrayList<java.security.cert.Certificate> certChains = new ArrayList<>();
+            for (int i = 0; i < signers.length; i++) {
+                certChains.addAll(
+                    signers[i].getSignerCertPath().getCertificates());
+            }
+
+            // Convert into a Certificate[]
+            return certChains.toArray(
+                    new java.security.cert.Certificate[certChains.size()]);
+        }
+        return null;
+    }
+
+    /**
+     * returns true if there no files to verify.
+     * should only be called after all the META-INF entries
+     * have been processed.
+     */
+    boolean nothingToVerify()
+    {
+        return (anyToVerify == false);
+    }
+
+    /**
+     * called to let us know we have processed all the
+     * META-INF entries, and if we re-read one of them, don't
+     * re-process it. Also gets rid of any data structures
+     * we needed when parsing META-INF entries.
+     */
+    void doneWithMeta()
+    {
+        parsingMeta = false;
+        anyToVerify = !sigFileSigners.isEmpty();
+        baos = null;
+        sigFileData = null;
+        pendingBlocks = null;
+        signerCache = null;
+        manDig = null;
+        // MANIFEST.MF is always treated as signed and verified,
+        // move its signers from sigFileSigners to verifiedSigners.
+        if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
+            CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
+            verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
+        }
+    }
+
+    static class VerifierStream extends java.io.InputStream {
+
+        private InputStream is;
+        private JarVerifier jv;
+        private ManifestEntryVerifier mev;
+        private long numLeft;
+
+        VerifierStream(Manifest man,
+                       JarEntry je,
+                       InputStream is,
+                       JarVerifier jv) throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            // To know that null signals that the stream has been closed, we disallow
+            // it in the constructor. There's no need for anyone to pass null into this
+            // constructor, anyway.
+            if (is == null) {
+                throw new NullPointerException("is == null");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            this.is = is;
+            this.jv = jv;
+            this.mev = new ManifestEntryVerifier(man);
+            this.jv.beginEntry(je, mev);
+            this.numLeft = je.getSize();
+            if (this.numLeft == 0)
+                this.jv.update(-1, this.mev);
+        }
+
+        public int read() throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (numLeft > 0) {
+                int b = is.read();
+                jv.update(b, mev);
+                numLeft--;
+                if (numLeft == 0)
+                    jv.update(-1, mev);
+                return b;
+            } else {
+                return -1;
+            }
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if ((numLeft > 0) && (numLeft < len)) {
+                len = (int)numLeft;
+            }
+
+            if (numLeft > 0) {
+                int n = is.read(b, off, len);
+                jv.update(n, b, off, len, mev);
+                numLeft -= n;
+                if (numLeft == 0)
+                    jv.update(-1, b, off, len, mev);
+                return n;
+            } else {
+                return -1;
+            }
+        }
+
+        public void close()
+            throws IOException
+        {
+            if (is != null)
+                is.close();
+            is = null;
+            mev = null;
+            jv = null;
+        }
+
+        public int available() throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            return is.available();
+        }
+
+    }
+
+    // Extended JavaUtilJarAccess CodeSource API Support
+
+    private Map<URL, Map<CodeSigner[], CodeSource>> urlToCodeSourceMap = new HashMap<>();
+    private Map<CodeSigner[], CodeSource> signerToCodeSource = new HashMap<>();
+    private URL lastURL;
+    private Map<CodeSigner[], CodeSource> lastURLMap;
+
+    /*
+     * Create a unique mapping from codeSigner cache entries to CodeSource.
+     * In theory, multiple URLs origins could map to a single locally cached
+     * and shared JAR file although in practice there will be a single URL in use.
+     */
+    private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) {
+        Map<CodeSigner[], CodeSource> map;
+        if (url == lastURL) {
+            map = lastURLMap;
+        } else {
+            map = urlToCodeSourceMap.get(url);
+            if (map == null) {
+                map = new HashMap<>();
+                urlToCodeSourceMap.put(url, map);
+            }
+            lastURLMap = map;
+            lastURL = url;
+        }
+        CodeSource cs = map.get(signers);
+        if (cs == null) {
+            cs = new VerifierCodeSource(csdomain, url, signers);
+            signerToCodeSource.put(signers, cs);
+        }
+        return cs;
+    }
+
+    private CodeSource[] mapSignersToCodeSources(URL url, List<CodeSigner[]> signers, boolean unsigned) {
+        List<CodeSource> sources = new ArrayList<>();
+
+        for (int i = 0; i < signers.size(); i++) {
+            sources.add(mapSignersToCodeSource(url, signers.get(i)));
+        }
+        if (unsigned) {
+            sources.add(mapSignersToCodeSource(url, null));
+        }
+        return sources.toArray(new CodeSource[sources.size()]);
+    }
+    private CodeSigner[] emptySigner = new CodeSigner[0];
+
+    /*
+     * Match CodeSource to a CodeSigner[] in the signer cache.
+     */
+    private CodeSigner[] findMatchingSigners(CodeSource cs) {
+        if (cs instanceof VerifierCodeSource) {
+            VerifierCodeSource vcs = (VerifierCodeSource) cs;
+            if (vcs.isSameDomain(csdomain)) {
+                return ((VerifierCodeSource) cs).getPrivateSigners();
+            }
+        }
+
+        /*
+         * In practice signers should always be optimized above
+         * but this handles a CodeSource of any type, just in case.
+         */
+        CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true);
+        List<CodeSource> sourceList = new ArrayList<>();
+        for (int i = 0; i < sources.length; i++) {
+            sourceList.add(sources[i]);
+        }
+        int j = sourceList.indexOf(cs);
+        if (j != -1) {
+            CodeSigner[] match;
+            match = ((VerifierCodeSource) sourceList.get(j)).getPrivateSigners();
+            if (match == null) {
+                match = emptySigner;
+            }
+            return match;
+        }
+        return null;
+    }
+
+    /*
+     * Instances of this class hold uncopied references to internal
+     * signing data that can be compared by object reference identity.
+     */
+    private static class VerifierCodeSource extends CodeSource {
+        private static final long serialVersionUID = -9047366145967768825L;
+
+        URL vlocation;
+        CodeSigner[] vsigners;
+        java.security.cert.Certificate[] vcerts;
+        Object csdomain;
+
+        VerifierCodeSource(Object csdomain, URL location, CodeSigner[] signers) {
+            super(location, signers);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vsigners = signers; // from signerCache
+        }
+
+        VerifierCodeSource(Object csdomain, URL location, java.security.cert.Certificate[] certs) {
+            super(location, certs);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vcerts = certs; // from signerCache
+        }
+
+        /*
+         * All VerifierCodeSource instances are constructed based on
+         * singleton signerCache or signerCacheCert entries for each unique signer.
+         * No CodeSigner<->Certificate[] conversion is required.
+         * We use these assumptions to optimize equality comparisons.
+         */
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof VerifierCodeSource) {
+                VerifierCodeSource that = (VerifierCodeSource) obj;
+
+                /*
+                 * Only compare against other per-signer singletons constructed
+                 * on behalf of the same JarFile instance. Otherwise, compare
+                 * things the slower way.
+                 */
+                if (isSameDomain(that.csdomain)) {
+                    if (that.vsigners != this.vsigners
+                            || that.vcerts != this.vcerts) {
+                        return false;
+                    }
+                    if (that.vlocation != null) {
+                        return that.vlocation.equals(this.vlocation);
+                    } else if (this.vlocation != null) {
+                        return this.vlocation.equals(that.vlocation);
+                    } else { // both null
+                        return true;
+                    }
+                }
+            }
+            return super.equals(obj);
+        }
+
+        boolean isSameDomain(Object csdomain) {
+            return this.csdomain == csdomain;
+        }
+
+        private CodeSigner[] getPrivateSigners() {
+            return vsigners;
+        }
+
+        private java.security.cert.Certificate[] getPrivateCertificates() {
+            return vcerts;
+        }
+    }
+    private Map<String, CodeSigner[]> signerMap;
+
+    private synchronized Map<String, CodeSigner[]> signerMap() {
+        if (signerMap == null) {
+            /*
+             * Snapshot signer state so it doesn't change on us. We care
+             * only about the asserted signatures. Verification of
+             * signature validity happens via the JarEntry apis.
+             */
+            signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size());
+            signerMap.putAll(verifiedSigners);
+            signerMap.putAll(sigFileSigners);
+        }
+        return signerMap;
+    }
+
+    public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Iterator<Map.Entry<String, CodeSigner[]>> itor = map.entrySet().iterator();
+        boolean matchUnsigned = false;
+
+        /*
+         * Grab a single copy of the CodeSigner arrays. Check
+         * to see if we can optimize CodeSigner equality test.
+         */
+        List<CodeSigner[]> req = new ArrayList<>(cs.length);
+        for (int i = 0; i < cs.length; i++) {
+            CodeSigner[] match = findMatchingSigners(cs[i]);
+            if (match != null) {
+                if (match.length > 0) {
+                    req.add(match);
+                } else {
+                    matchUnsigned = true;
+                }
+            } else {
+                matchUnsigned = true;
+            }
+        }
+
+        final List<CodeSigner[]> signersReq = req;
+        final Enumeration<String> enum2 = (matchUnsigned) ? unsignedEntryNames(jar) : emptyEnumeration;
+
+        return new Enumeration<String>() {
+
+            String name;
+
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+
+                while (itor.hasNext()) {
+                    Map.Entry<String, CodeSigner[]> e = itor.next();
+                    if (signersReq.contains(e.getValue())) {
+                        name = e.getKey();
+                        return true;
+                    }
+                }
+                while (enum2.hasMoreElements()) {
+                    name = enum2.nextElement();
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    /*
+     * Like entries() but screens out internal JAR mechanism entries
+     * and includes signed entries with no ZIP data.
+     */
+    public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration<? extends ZipEntry> e) {
+        final Map<String, CodeSigner[]> map = new HashMap<>();
+        map.putAll(signerMap());
+        final Enumeration<? extends ZipEntry> enum_ = e;
+        return new Enumeration<JarEntry>() {
+
+            Enumeration<String> signers = null;
+            JarEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = jar.newEntry(ze);
+                    return true;
+                }
+                if (signers == null) {
+                    signers = Collections.enumeration(map.keySet());
+                }
+                while (signers.hasMoreElements()) {
+                    String name = signers.nextElement();
+                    entry = jar.newEntry(new ZipEntry(name));
+                    return true;
+                }
+
+                // Any map entries left?
+                return false;
+            }
+
+            public JarEntry nextElement() {
+                if (hasMoreElements()) {
+                    JarEntry je = entry;
+                    map.remove(je.getName());
+                    entry = null;
+                    return je;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private Enumeration<String> emptyEnumeration = new Enumeration<String>() {
+
+        public boolean hasMoreElements() {
+            return false;
+        }
+
+        public String nextElement() {
+            throw new NoSuchElementException();
+        }
+    };
+
+    // true if file is part of the signature mechanism itself
+    static boolean isSigningRelated(String name) {
+        return SignatureFileVerifier.isSigningRelated(name);
+    }
+
+    private Enumeration<String> unsignedEntryNames(JarFile jar) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Enumeration<JarEntry> entries = jar.entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             */
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || isSigningRelated(value)) {
+                        continue;
+                    }
+                    if (map.get(value) == null) {
+                        name = value;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private List<CodeSigner[]> jarCodeSigners;
+
+    private synchronized List<CodeSigner[]> getJarCodeSigners() {
+        CodeSigner[] signers;
+        if (jarCodeSigners == null) {
+            HashSet<CodeSigner[]> set = new HashSet<>();
+            set.addAll(signerMap().values());
+            jarCodeSigners = new ArrayList<>();
+            jarCodeSigners.addAll(set);
+        }
+        return jarCodeSigners;
+    }
+
+    public synchronized CodeSource[] getCodeSources(JarFile jar, URL url) {
+        boolean hasUnsigned = unsignedEntryNames(jar).hasMoreElements();
+
+        return mapSignersToCodeSources(url, getJarCodeSigners(), hasUnsigned);
+    }
+
+    public CodeSource getCodeSource(URL url, String name) {
+        CodeSigner[] signers;
+
+        signers = signerMap().get(name);
+        return mapSignersToCodeSource(url, signers);
+    }
+
+    public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) {
+        CodeSigner[] signers;
+
+        return mapSignersToCodeSource(url, getCodeSigners(jar, je));
+    }
+
+    public void setEagerValidation(boolean eager) {
+        eagerValidation = eager;
+    }
+
+    public synchronized List<Object> getManifestDigests() {
+        return Collections.unmodifiableList(manifestDigests);
+    }
+
+    static CodeSource getUnsignedCS(URL url) {
+        return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null);
+    }
+
+    /**
+     * Returns whether the name is trusted. Used by
+     * {@link Manifest#getTrustedAttributes(String)}.
+     */
+    boolean isTrustedManifestEntry(String name) {
+        // How many signers? MANIFEST.MF is always verified
+        CodeSigner[] forMan = verifiedSigners.get(manifestName);
+        if (forMan == null) {
+            return true;
+        }
+        // Check sigFileSigners first, because we are mainly dealing with
+        // non-file entries which will stay in sigFileSigners forever.
+        CodeSigner[] forName = sigFileSigners.get(name);
+        if (forName == null) {
+            forName = verifiedSigners.get(name);
+        }
+        // Returns trusted if all signers sign the entry
+        return forName != null && forName.length == forMan.length;
+    }
+}
diff --git a/android-35/java/util/jar/Manifest.java b/android-35/java/util/jar/Manifest.java
new file mode 100644
index 0000000..8b16a36
--- /dev/null
+++ b/android-35/java/util/jar/Manifest.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.DataOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import sun.security.util.SecurityProperties;
+
+/**
+ * The Manifest class is used to maintain Manifest entry names and their
+ * associated Attributes. There are main Manifest Attributes as well as
+ * per-entry Attributes. For information on the Manifest format, please
+ * see the
+ * <a href="{@docRoot}/../specs/jar/jar.html">
+ * Manifest format specification</a>.
+ *
+ * @author  David Connelly
+ * @see     Attributes
+ * @since   1.2
+ */
+public class Manifest implements Cloneable {
+
+    // manifest main attributes
+    private final Attributes attr = new Attributes();
+
+    // manifest entries
+    private final Map<String, Attributes> entries = new HashMap<>();
+
+    // associated JarVerifier, not null when called by JarFile::getManifest.
+    private final JarVerifier jv;
+
+    /**
+     * Constructs a new, empty Manifest.
+     */
+    public Manifest() {
+        jv = null;
+    }
+
+    /**
+     * Constructs a new Manifest from the specified input stream.
+     *
+     * @param is the input stream containing manifest data
+     * @throws IOException if an I/O error has occurred
+     */
+    public Manifest(InputStream is) throws IOException {
+        this(null, is, null);
+    }
+
+    /**
+     * Constructs a new Manifest from the specified input stream.
+     *
+     * @param is the input stream containing manifest data
+     * @param jarFilename the name of the corresponding jar archive if available
+     * @throws IOException if an I/O error has occurred
+     */
+    Manifest(InputStream is, String jarFilename) throws IOException {
+        this(null, is, jarFilename);
+    }
+
+    /**
+     * Constructs a new Manifest from the specified input stream
+     * and associates it with a JarVerifier.
+     *
+     * @param jv the JarVerifier to use
+     * @param is the input stream containing manifest data
+     * @param jarFilename the name of the corresponding jar archive if available
+     * @throws IOException if an I/O error has occurred
+     */
+    Manifest(JarVerifier jv, InputStream is, String jarFilename) throws IOException {
+        read(is, jarFilename);
+        this.jv = jv;
+    }
+
+    /**
+     * Constructs a new Manifest that is a copy of the specified Manifest.
+     *
+     * @param man the Manifest to copy
+     */
+    public Manifest(Manifest man) {
+        attr.putAll(man.getMainAttributes());
+        entries.putAll(man.getEntries());
+        jv = man.jv;
+    }
+
+    /**
+     * Returns the main Attributes for the Manifest.
+     * @return the main Attributes for the Manifest
+     */
+    public Attributes getMainAttributes() {
+        return attr;
+    }
+
+    /**
+     * Returns a Map of the entries contained in this Manifest. Each entry
+     * is represented by a String name (key) and associated Attributes (value).
+     * The Map permits the {@code null} key, but no entry with a null key is
+     * created by {@link #read}, nor is such an entry written by using {@link
+     * #write}.
+     *
+     * @return a Map of the entries contained in this Manifest
+     */
+    public Map<String,Attributes> getEntries() {
+        return entries;
+    }
+
+    /**
+     * Returns the Attributes for the specified entry name.
+     * This method is defined as:
+     * <pre>
+     *      return (Attributes)getEntries().get(name)
+     * </pre>
+     * Though {@code null} is a valid {@code name}, when
+     * {@code getAttributes(null)} is invoked on a {@code Manifest}
+     * obtained from a jar file, {@code null} will be returned.  While jar
+     * files themselves do not allow {@code null}-named attributes, it is
+     * possible to invoke {@link #getEntries} on a {@code Manifest}, and
+     * on that result, invoke {@code put} with a null key and an
+     * arbitrary value.  Subsequent invocations of
+     * {@code getAttributes(null)} will return the just-{@code put}
+     * value.
+     * <p>
+     * Note that this method does not return the manifest's main attributes;
+     * see {@link #getMainAttributes}.
+     *
+     * @param name entry name
+     * @return the Attributes for the specified entry name
+     */
+    public Attributes getAttributes(String name) {
+        return getEntries().get(name);
+    }
+
+    /**
+     * Returns the Attributes for the specified entry name, if trusted.
+     *
+     * @param name entry name
+     * @return returns the same result as {@link #getAttributes(String)}
+     * @throws SecurityException if the associated jar is signed but this entry
+     *      has been modified after signing (i.e. the section in the manifest
+     *      does not exist in SF files of all signers).
+     */
+    Attributes getTrustedAttributes(String name) {
+        // Note: Before the verification of MANIFEST.MF/.SF/.RSA files is done,
+        // jv.isTrustedManifestEntry() isn't able to detect MANIFEST.MF change.
+        // Users of this method should call SharedSecrets.javaUtilJarAccess()
+        // .ensureInitialization() first.
+        Attributes result = getAttributes(name);
+        if (result != null && jv != null && ! jv.isTrustedManifestEntry(name)) {
+            throw new SecurityException("Untrusted manifest entry: " + name);
+        }
+        return result;
+    }
+
+    /**
+     * Clears the main Attributes as well as the entries in this Manifest.
+     */
+    public void clear() {
+        attr.clear();
+        entries.clear();
+    }
+
+    /**
+     * Writes the Manifest to the specified OutputStream.
+     * Attributes.Name.MANIFEST_VERSION must be set in
+     * MainAttributes prior to invoking this method.
+     *
+     * @param out the output stream
+     * @throws    IOException if an I/O error has occurred
+     * @see #getMainAttributes
+     */
+    public void write(OutputStream out) throws IOException {
+        DataOutputStream dos = new DataOutputStream(out);
+        // Write out the main attributes for the manifest
+        attr.writeMain(dos);
+        // Now write out the per-entry attributes
+        StringBuilder buffer = entries.isEmpty() ? null : new StringBuilder(72);
+        for (Map.Entry<String, Attributes> e : entries.entrySet()) {
+            buffer.setLength(0);
+            buffer.append("Name: ");
+            buffer.append(e.getKey());
+            println72(dos, buffer.toString());
+            e.getValue().write(dos);
+        }
+        dos.flush();
+    }
+
+    /**
+     * Adds line breaks to enforce a maximum of 72 bytes per line.
+     *
+     * @deprecation Replaced with {@link #println72}.
+     */
+    @Deprecated(since = "13")
+    static void make72Safe(StringBuffer line) {
+        int length = line.length();
+        int index = 72;
+        while (index < length) {
+            line.insert(index, "\r\n ");
+            index += 74; // + line width + line break ("\r\n")
+            length += 3; // + line break ("\r\n") and space
+        }
+    }
+
+    /**
+     * Writes {@code line} to {@code out} with line breaks and continuation
+     * spaces within the limits of 72 bytes of contents per line followed
+     * by a line break.
+     */
+    static void println72(OutputStream out, String line) throws IOException {
+        if (!line.isEmpty()) {
+            byte[] lineBytes = line.getBytes(UTF_8);
+            int length = lineBytes.length;
+            // first line can hold one byte more than subsequent lines which
+            // start with a continuation line break space
+            out.write(lineBytes[0]);
+            int pos = 1;
+            while (length - pos > 71) {
+                out.write(lineBytes, pos, 71);
+                pos += 71;
+                println(out);
+                out.write(' ');
+            }
+            out.write(lineBytes, pos, length - pos);
+        }
+        println(out);
+    }
+
+    /**
+     * Writes a line break to {@code out}.
+     */
+    static void println(OutputStream out) throws IOException {
+        out.write('\r');
+        out.write('\n');
+    }
+
+    static String getErrorPosition(String filename, final int lineNumber) {
+        if (filename == null ||
+                !SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS) {
+            return "line " + lineNumber;
+        }
+        return "manifest of " + filename + ":" + lineNumber;
+    }
+
+    /**
+     * Reads the Manifest from the specified InputStream. The entry
+     * names and attributes read will be merged in with the current
+     * manifest entries.
+     *
+     * @param is the input stream
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void read(InputStream is) throws IOException {
+        read(is, null);
+    }
+
+    private void read(InputStream is, String jarFilename) throws IOException {
+        // Buffered input stream for reading manifest data
+        FastInputStream fis = new FastInputStream(is);
+        // Line buffer
+        byte[] lbuf = new byte[512];
+        // Read the main attributes for the manifest
+        int lineNumber = attr.read(fis, lbuf, jarFilename, 0);
+        // Total number of entries, attributes read
+        int ecount = 0, acount = 0;
+        // Average size of entry attributes
+        int asize = 2;
+        // Now parse the manifest entries
+        int len;
+        String name = null;
+        boolean skipEmptyLines = true;
+        byte[] lastline = null;
+
+        while ((len = fis.readLine(lbuf)) != -1) {
+            byte c = lbuf[--len];
+            lineNumber++;
+
+            if (c != '\n' && c != '\r') {
+                throw new IOException("manifest line too long ("
+                           + getErrorPosition(jarFilename, lineNumber) + ")");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0 && skipEmptyLines) {
+                continue;
+            }
+            skipEmptyLines = false;
+
+            if (name == null) {
+                name = parseName(lbuf, len);
+                if (name == null) {
+                    throw new IOException("invalid manifest format ("
+                              + getErrorPosition(jarFilename, lineNumber) + ")");
+                }
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = new byte[len - 6];
+                    System.arraycopy(lbuf, 6, lastline, 0, len - 6);
+                    continue;
+                }
+            } else {
+                // continuation line
+                byte[] buf = new byte[lastline.length + len - 1];
+                System.arraycopy(lastline, 0, buf, 0, lastline.length);
+                System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = buf;
+                    continue;
+                }
+                name = new String(buf, 0, buf.length, UTF_8);
+                lastline = null;
+            }
+            Attributes attr = getAttributes(name);
+            if (attr == null) {
+                attr = new Attributes(asize);
+                entries.put(name, attr);
+            }
+            lineNumber = attr.read(fis, lbuf, jarFilename, lineNumber);
+            ecount++;
+            acount += attr.size();
+            //XXX: Fix for when the average is 0. When it is 0,
+            // you get an Attributes object with an initial
+            // capacity of 0, which tickles a bug in HashMap.
+            asize = Math.max(2, acount / ecount);
+
+            name = null;
+            skipEmptyLines = true;
+        }
+    }
+
+    private String parseName(byte[] lbuf, int len) {
+        if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' &&
+            toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' &&
+            lbuf[4] == ':' && lbuf[5] == ' ') {
+            return new String(lbuf, 6, len - 6, UTF_8);
+        }
+        return null;
+    }
+
+    private int toLower(int c) {
+        return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c;
+    }
+
+    /**
+     * Returns true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries.
+     *
+     * @param o the object to be compared
+     * @return true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries
+     */
+    public boolean equals(Object o) {
+        // TODO(b/248243024) Revert this.
+        /*
+        return o instanceof Manifest m
+                && attr.equals(m.getMainAttributes())
+                && entries.equals(m.getEntries());
+        */
+        if (o instanceof Manifest) {
+            Manifest other = (Manifest) o;
+
+            return attr.equals(other.getMainAttributes())
+                    && entries.equals(other.getEntries());
+        }
+        return false;
+    }
+
+    /**
+     * Returns the hash code for this Manifest.
+     */
+    public int hashCode() {
+        return attr.hashCode() + entries.hashCode();
+    }
+
+    /**
+     * Returns a shallow copy of this Manifest.  The shallow copy is
+     * implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Manifest(this); }
+     * </pre>
+     * @return a shallow copy of this Manifest
+     */
+    public Object clone() {
+        return new Manifest(this);
+    }
+
+    /*
+     * A fast buffered input stream for parsing manifest files.
+     */
+    static class FastInputStream extends FilterInputStream {
+        private byte buf[];
+        private int count = 0;
+        private int pos = 0;
+
+        FastInputStream(InputStream in) {
+            this(in, 8192);
+        }
+
+        FastInputStream(InputStream in, int size) {
+            super(in);
+            buf = new byte[size];
+        }
+
+        public int read() throws IOException {
+            if (pos >= count) {
+                fill();
+                if (pos >= count) {
+                    return -1;
+                }
+            }
+            return Byte.toUnsignedInt(buf[pos++]);
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            int avail = count - pos;
+            if (avail <= 0) {
+                if (len >= buf.length) {
+                    return in.read(b, off, len);
+                }
+                fill();
+                avail = count - pos;
+                if (avail <= 0) {
+                    return -1;
+                }
+            }
+            if (len > avail) {
+                len = avail;
+            }
+            System.arraycopy(buf, pos, b, off, len);
+            pos += len;
+            return len;
+        }
+
+        /*
+         * Reads 'len' bytes from the input stream, or until an end-of-line
+         * is reached. Returns the number of bytes read.
+         */
+        public int readLine(byte[] b, int off, int len) throws IOException {
+            byte[] tbuf = this.buf;
+            int total = 0;
+            while (total < len) {
+                int avail = count - pos;
+                if (avail <= 0) {
+                    fill();
+                    avail = count - pos;
+                    if (avail <= 0) {
+                        return -1;
+                    }
+                }
+                int n = len - total;
+                if (n > avail) {
+                    n = avail;
+                }
+                int tpos = pos;
+                int maxpos = tpos + n;
+                byte c = 0;
+                // jar.spec.newline: CRLF | LF | CR (not followed by LF)
+                while (tpos < maxpos && (c = tbuf[tpos++]) != '\n' && c != '\r');
+                if (c == '\r' && tpos < maxpos && tbuf[tpos] == '\n') {
+                    tpos++;
+                }
+                n = tpos - pos;
+                System.arraycopy(tbuf, pos, b, off, n);
+                off += n;
+                total += n;
+                pos = tpos;
+                c = tbuf[tpos-1];
+                if (c == '\n') {
+                    break;
+                }
+                if (c == '\r') {
+                    if (count == pos) {
+                        // try to see if there is a trailing LF
+                        fill();
+                        if (pos < count && tbuf[pos] == '\n') {
+                            if (total < len) {
+                                b[off++] = '\n';
+                                total++;
+                            } else {
+                                // we should always have big enough lbuf but
+                                // just in case we don't, replace the last CR
+                                // with LF.
+                                b[off - 1] = '\n';
+                            }
+                            pos++;
+                        }
+                    }
+                    break;
+                }
+            }
+            return total;
+        }
+
+        public byte peek() throws IOException {
+            if (pos == count)
+                fill();
+            if (pos == count)
+                return -1; // nothing left in buffer
+            return buf[pos];
+        }
+
+        public int readLine(byte[] b) throws IOException {
+            return readLine(b, 0, b.length);
+        }
+
+        public long skip(long n) throws IOException {
+            if (n <= 0) {
+                return 0;
+            }
+            long avail = count - pos;
+            if (avail <= 0) {
+                return in.skip(n);
+            }
+            if (n > avail) {
+                n = avail;
+            }
+            pos += n;
+            return n;
+        }
+
+        public int available() throws IOException {
+            return (count - pos) + in.available();
+        }
+
+        public void close() throws IOException {
+            if (in != null) {
+                in.close();
+                in = null;
+                buf = null;
+            }
+        }
+
+        private void fill() throws IOException {
+            count = pos = 0;
+            int n = in.read(buf, 0, buf.length);
+            if (n > 0) {
+                count = n;
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/jar/Pack200.java b/android-35/java/util/jar/Pack200.java
new file mode 100644
index 0000000..9211f0a
--- /dev/null
+++ b/android-35/java/util/jar/Pack200.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.jar;
+
+import java.util.SortedMap;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.beans.PropertyChangeListener;
+
+
+
+
+/**
+ * Transforms a JAR file to or from a packed stream in Pack200 format.
+ * Please refer to Network Transfer Format JSR 200 Specification at
+ * <a href=http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html>http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html</a>
+ * <p>
+ * Typically the packer engine is used by application developers
+ * to deploy or host JAR files on a website.
+ * The unpacker  engine is used by deployment applications to
+ * transform the byte-stream back to JAR format.
+ * <p>
+ * Here is an example using  packer and unpacker:
+ * <pre>{@code
+ *    import java.util.jar.Pack200;
+ *    import java.util.jar.Pack200.*;
+ *    ...
+ *    // Create the Packer object
+ *    Packer packer = Pack200.newPacker();
+ *
+ *    // Initialize the state by setting the desired properties
+ *    Map p = packer.properties();
+ *    // take more time choosing codings for better compression
+ *    p.put(Packer.EFFORT, "7");  // default is "5"
+ *    // use largest-possible archive segments (>10% better compression).
+ *    p.put(Packer.SEGMENT_LIMIT, "-1");
+ *    // reorder files for better compression.
+ *    p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE);
+ *    // smear modification times to a single value.
+ *    p.put(Packer.MODIFICATION_TIME, Packer.LATEST);
+ *    // ignore all JAR deflation requests,
+ *    // transmitting a single request to use "store" mode.
+ *    p.put(Packer.DEFLATE_HINT, Packer.FALSE);
+ *    // discard debug attributes
+ *    p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP);
+ *    // throw an error if an attribute is unrecognized
+ *    p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
+ *    // pass one class file uncompressed:
+ *    p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class");
+ *    try {
+ *        JarFile jarFile = new JarFile("/tmp/testref.jar");
+ *        FileOutputStream fos = new FileOutputStream("/tmp/test.pack");
+ *        // Call the packer
+ *        packer.pack(jarFile, fos);
+ *        jarFile.close();
+ *        fos.close();
+ *
+ *        File f = new File("/tmp/test.pack");
+ *        FileOutputStream fostream = new FileOutputStream("/tmp/test.jar");
+ *        JarOutputStream jostream = new JarOutputStream(fostream);
+ *        Unpacker unpacker = Pack200.newUnpacker();
+ *        // Call the unpacker
+ *        unpacker.unpack(f, jostream);
+ *        // Must explicitly close the output.
+ *        jostream.close();
+ *    } catch (IOException ioe) {
+ *        ioe.printStackTrace();
+ *    }
+ * }</pre>
+ * <p>
+ * A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers.
+ * The deployment applications can use "Accept-Encoding=pack200-gzip". This
+ * indicates to the server that the client application desires a version of
+ * the file encoded with Pack200 and further compressed with gzip. Please
+ * refer to  <a href="{@docRoot}/../technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
+ * techniques.
+ * <p>
+ * Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ * @author John Rose
+ * @author Kumar Srinivasan
+ * @since 1.5
+ */
+public abstract class Pack200 {
+    private Pack200() {} //prevent instantiation
+
+    // Static methods of the Pack200 class.
+    /**
+     * Obtain new instance of a class that implements Packer.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Packer</tt>
+     * is defined, then the value is taken to be the fully-qualified name
+     * of a concrete implementation class, which must implement Packer.
+     * This class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the system
+     * property, then the system-default implementation class is instantiated,
+     * and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * packer engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Packer engine.
+     */
+    public synchronized static Packer newPacker() {
+        return (Packer) newInstance(PACK_PROVIDER);
+    }
+
+
+    /**
+     * Obtain new instance of a class that implements Unpacker.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Unpacker</tt>
+     * is defined, then the value is taken to be the fully-qualified
+     * name of a concrete implementation class, which must implement Unpacker.
+     * The class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the
+     * system property, then the system-default implementation class
+     * is instantiated, and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * unpacker engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Unpacker engine.
+     */
+
+    public static Unpacker newUnpacker() {
+        return (Unpacker) newInstance(UNPACK_PROVIDER);
+    }
+
+    // Interfaces
+    /**
+     * The packer engine applies various transformations to the input JAR file,
+     * making the pack stream highly compressible by a compressor such as
+     * gzip or zip. An instance of the engine can be obtained
+     * using {@link #newPacker}.
+
+     * The high degree of compression is achieved
+     * by using a number of techniques described in the JSR 200 specification.
+     * Some of the techniques are sorting, re-ordering and co-location of the
+     * constant pool.
+     * <p>
+     * The pack engine is initialized to an initial state as described
+     * by their properties below.
+     * The initial state can be manipulated by getting the
+     * engine properties (using {@link #properties}) and storing
+     * the modified properties on the map.
+     * The resource files will be passed through with no changes at all.
+     * The class files will not contain identical bytes, since the unpacker
+     * is free to change minor class file features such as constant pool order.
+     * However, the class files will be semantically identical,
+     * as specified in
+     * <cite>The Java&trade; Virtual Machine Specification</cite>.
+     * <p>
+     * By default, the packer does not change the order of JAR elements.
+     * Also, the modification time and deflation hint of each
+     * JAR element is passed unchanged.
+     * (Any other ZIP-archive information, such as extra attributes
+     * giving Unix file permissions, are lost.)
+     * <p>
+     * Note that packing and unpacking a JAR will in general alter the
+     * bytewise contents of classfiles in the JAR.  This means that packing
+     * and unpacking will in general invalidate any digital signatures
+     * which rely on bytewise images of JAR elements.  In order both to sign
+     * and to pack a JAR, you must first pack and unpack the JAR to
+     * "normalize" it, then compute signatures on the unpacked JAR elements,
+     * and finally repack the signed JAR.
+     * Both packing steps should
+     * use precisely the same options, and the segment limit may also
+     * need to be set to "-1", to prevent accidental variation of segment
+     * boundaries as class file sizes change slightly.
+     * <p>
+     * (Here's why this works:  Any reordering the packer does
+     * of any classfile structures is idempotent, so the second packing
+     * does not change the orderings produced by the first packing.
+     * Also, the unpacker is guaranteed by the JSR 200 specification
+     * to produce a specific bytewise image for any given transmission
+     * ordering of archive elements.)
+     * <p>
+     * In order to maintain backward compatibility, the pack file's version is
+     * set to accommodate the class files present in the input JAR file. In
+     * other words, the pack file version will be the latest, if the class files
+     * are the latest and conversely the pack file version will be the oldest
+     * if the class file versions are also the oldest. For intermediate class
+     * file versions the corresponding pack file version will be used.
+     * For example:
+     *    If the input JAR-files are solely comprised of 1.5  (or  lesser)
+     * class files, a 1.5 compatible pack file is  produced. This will also be
+     * the case for archives that have no class files.
+     *    If the input JAR-files contains a 1.6 class file, then the pack file
+     * version will be set to 1.6.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * @since 1.5
+     */
+    public interface Packer {
+        /**
+         * This property is a numeral giving the estimated target size N
+         * (in bytes) of each archive segment.
+         * If a single input file requires more than N bytes,
+         * it will be given its own archive segment.
+         * <p>
+         * As a special case, a value of -1 will produce a single large
+         * segment with all input files, while a value of 0 will
+         * produce one segment for each class.
+         * Larger archive segments result in less fragmentation and
+         * better compression, but processing them requires more memory.
+         * <p>
+         * The size of each segment is estimated by counting the size of each
+         * input file to be transmitted in the segment, along with the size
+         * of its name and other transmitted properties.
+         * <p>
+         * The default is -1, which means the packer will always create a single
+         * segment output file. In cases where extremely large output files are
+         * generated, users are strongly encouraged to use segmenting or break
+         * up the input file into smaller JARs.
+         * <p>
+         * A 10Mb JAR packed without this limit will
+         * typically pack about 10% smaller, but the packer may require
+         * a larger Java heap (about ten times the segment limit).
+         */
+        String SEGMENT_LIMIT    = "pack.segment.limit";
+
+        /**
+         * If this property is set to {@link #TRUE}, the packer will transmit
+         * all elements in their original order within the source archive.
+         * <p>
+         * If it is set to {@link #FALSE}, the packer may reorder elements,
+         * and also remove JAR directory entries, which carry no useful
+         * information for Java applications.
+         * (Typically this enables better compression.)
+         * <p>
+         * The default is {@link #TRUE}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         */
+        String KEEP_FILE_ORDER = "pack.keep.file.order";
+
+
+        /**
+         * If this property is set to a single decimal digit, the packer will
+         * use the indicated amount of effort in compressing the archive.
+         * Level 1 may produce somewhat larger size and faster compression speed,
+         * while level 9 will take much longer but may produce better compression.
+         * <p>
+         * The special value 0 instructs the packer to copy through the
+         * original JAR file directly, with no compression.  The JSR 200
+         * standard requires any unpacker to understand this special case
+         * as a pass-through of the entire archive.
+         * <p>
+         * The default is 5, investing a modest amount of time to
+         * produce reasonable compression.
+         */
+        String EFFORT           = "pack.effort";
+
+        /**
+         * If this property is set to {@link #TRUE} or {@link #FALSE}, the packer
+         * will set the deflation hint accordingly in the output archive, and
+         * will not transmit the individual deflation hints of archive elements.
+         * <p>
+         * If this property is set to the special string {@link #KEEP}, the packer
+         * will attempt to determine an independent deflation hint for each
+         * available element of the input archive, and transmit this hint separately.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation
+         * to take action upon the hint to suitably compress the elements of
+         * the resulting unpacked jar.
+         * <p>
+         * The deflation hint of a ZIP or JAR element indicates
+         * whether the element was deflated or stored directly.
+         */
+        String DEFLATE_HINT     = "pack.deflate.hint";
+
+        /**
+         * If this property is set to the special string {@link #LATEST},
+         * the packer will attempt to determine the latest modification time,
+         * among all the available entries in the original archive or the latest
+         * modification time of all the available entries in each segment.
+         * This single value will be transmitted as part of the segment and applied
+         * to all the entries in each segment, {@link #SEGMENT_LIMIT}.
+         * <p>
+         * This can marginally decrease the transmitted size of the
+         * archive, at the expense of setting all installed files to a single
+         * date.
+         * <p>
+         * If this property is set to the special string {@link #KEEP},
+         * the packer transmits a separate modification time for each input
+         * element.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation to take action to suitably
+         * set the modification time of each element of its output file.
+         * @see #SEGMENT_LIMIT
+         */
+        String MODIFICATION_TIME        = "pack.modification.time";
+
+        /**
+         * Indicates that a file should be passed through bytewise, with no
+         * compression.  Multiple files may be specified by specifying
+         * additional properties with distinct strings appended, to
+         * make a family of properties with the common prefix.
+         * <p>
+         * There is no pathname transformation, except
+         * that the system file separator is replaced by the JAR file
+         * separator '/'.
+         * <p>
+         * The resulting file names must match exactly as strings with their
+         * occurrences in the JAR file.
+         * <p>
+         * If a property value is a directory name, all files under that
+         * directory will be passed also.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = packer.properties();
+         *     p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");
+         *     p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");
+         *     p.put(PASS_FILE_PFX+2, "mutants/Storm.class");
+         *     # Pass all files in an entire directory hierarchy:
+         *     p.put(PASS_FILE_PFX+3, "police/");
+         * }</pre>
+         */
+        String PASS_FILE_PFX            = "pack.pass.file.";
+
+        /// Attribute control.
+
+        /**
+         * Indicates the action to take when a class-file containing an unknown
+         * attribute is encountered.  Possible values are the strings {@link #ERROR},
+         * {@link #STRIP}, and {@link #PASS}.
+         * <p>
+         * The string {@link #ERROR} means that the pack operation
+         * as a whole will fail, with an exception of type <code>IOException</code>.
+         * The string
+         * {@link #STRIP} means that the attribute will be dropped.
+         * The string
+         * {@link #PASS} means that the whole class-file will be passed through
+         * (as if it were a resource file) without compression, with  a suitable warning.
+         * This is the default value for this property.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = pack200.getProperties();
+         *     p.put(UNKNOWN_ATTRIBUTE, ERROR);
+         *     p.put(UNKNOWN_ATTRIBUTE, STRIP);
+         *     p.put(UNKNOWN_ATTRIBUTE, PASS);
+         * }</pre>
+         */
+        String UNKNOWN_ATTRIBUTE        = "pack.unknown.attribute";
+
+        /**
+         * When concatenated with a class attribute name,
+         * indicates the format of that attribute,
+         * using the layout language specified in the JSR 200 specification.
+         * <p>
+         * For example, the effect of this option is built in:
+         * <code>pack.class.attribute.SourceFile=RUH</code>.
+         * <p>
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are
+         * also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}.
+         * This provides a way for users to request that specific attributes be
+         * refused, stripped, or passed bitwise (with no class compression).
+         * <p>
+         * Code like this might be used to support attributes for JCOV:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"CoverageTable",       "NH[PHHII]");
+         *     p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceID",           "RUH");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"CompilationID",      "RUH");
+         * </code></pre>
+         * <p>
+         * Code like this might be used to strip debugging attributes:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable",    STRIP);
+         *     p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP);
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceFile",        STRIP);
+         * </code></pre>
+         */
+        String CLASS_ATTRIBUTE_PFX      = "pack.class.attribute.";
+
+        /**
+         * When concatenated with a field attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.field.attribute.Deprecated=</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and
+         * {@link #PASS} are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String FIELD_ATTRIBUTE_PFX      = "pack.field.attribute.";
+
+        /**
+         * When concatenated with a method attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.method.attribute.Exceptions=NH[RCH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String METHOD_ATTRIBUTE_PFX     = "pack.method.attribute.";
+
+        /**
+         * When concatenated with a code attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String CODE_ATTRIBUTE_PFX       = "pack.code.attribute.";
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS                 = "pack.progress";
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         * @see #MODIFICATION_TIME
+         */
+        String KEEP  = "keep";
+
+        /** The string "pass", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String PASS  = "pass";
+
+        /** The string "strip", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String STRIP = "strip";
+
+        /** The string "error", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String ERROR = "error";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /** The string "latest", a possible value for certain properties.
+         * @see #MODIFICATION_TIME
+         */
+        String LATEST = "latest";
+
+        /**
+         * Get the set of this engine's properties.
+         * This set is a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * <p>
+         * The returned map implements all optional {@link SortedMap} operations
+         * @return A sorted association of property key strings to property
+         * values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Takes a JarFile and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * @param in a JarFile
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarFile in, OutputStream out) throws IOException ;
+
+        /**
+         * Takes a JarInputStream and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * <p>
+         * The modification time and deflation hint attributes are not available,
+         * for the JAR manifest file and its containing directory.
+         *
+         * @see #MODIFICATION_TIME
+         * @see #DEFLATE_HINT
+         * @param in a JarInputStream
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarInputStream in, OutputStream out) throws IOException ;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the packer
+         *             can poll the value of the {@link #PROGRESS PROGRESS}
+         *             property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    /**
+     * The unpacker engine converts the packed stream to a JAR file.
+     * An instance of the engine can be obtained
+     * using {@link #newUnpacker}.
+     * <p>
+     * Every JAR file produced by this engine will include the string
+     * "<tt>PACK200</tt>" as a zip file comment.
+     * This allows a deployer to detect if a JAR archive was packed and unpacked.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * This version of the unpacker is compatible with all previous versions.
+     * @since 1.5
+     */
+    public interface Unpacker {
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String KEEP  = "keep";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /**
+         * Property indicating that the unpacker should
+         * ignore all transmitted values for DEFLATE_HINT,
+         * replacing them by the given value, {@link #TRUE} or {@link #FALSE}.
+         * The default value is the special string {@link #KEEP},
+         * which asks the unpacker to preserve all transmitted
+         * deflation hints.
+         */
+        String DEFLATE_HINT      = "unpack.deflate.hint";
+
+
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS         = "unpack.progress";
+
+        /**
+         * Get the set of this engine's properties. This set is
+         * a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * @return A sorted association of option key strings to option values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * The entire contents of the input stream will be read.
+         * It may be more efficient to read the Pack200 archive
+         * to a file and pass the File object, using the alternate
+         * method described below.
+         * <p>
+         * Closes its input but not its output.  (The output can accumulate more elements.)
+         * @param in an InputStream.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(InputStream in, JarOutputStream out) throws IOException;
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * <p>
+         * Does not close its output.  (The output can accumulate more elements.)
+         * @param in a File.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(File in, JarOutputStream out) throws IOException;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the
+         *             unpacker can poll the value of the {@link #PROGRESS
+         *             PROGRESS} property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    // Private stuff....
+
+    private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer";
+    private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker";
+
+    private static Class<?> packerImpl;
+    private static Class<?> unpackerImpl;
+
+    private synchronized static Object newInstance(String prop) {
+        String implName = "(unknown)";
+        try {
+            Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
+            if (impl == null) {
+                // The first time, we must decide which class to use.
+                implName = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(prop,""));
+                if (implName != null && !implName.equals(""))
+                    impl = Class.forName(implName);
+                // Android-changed: Remove default Packer Impl.
+                //
+                // else if (PACK_PROVIDER.equals(prop))
+                //     impl = com.sun.java.util.jar.pack.PackerImpl.class;
+                // else
+                //    impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
+            }
+            // We have a class.  Now instantiate it.
+            return impl.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new Error("Class not found: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (InstantiationException e) {
+            throw new Error("Could not instantiate: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (IllegalAccessException e) {
+            throw new Error("Cannot access class: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        }
+    }
+
+}
diff --git a/android-35/java/util/jar/package-info.java b/android-35/java/util/jar/package-info.java
new file mode 100644
index 0000000..4ebf8d3
--- /dev/null
+++ b/android-35/java/util/jar/package-info.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes for reading and writing the JAR (Java ARchive)
+ * file format, which is based on the standard ZIP file format with an
+ * optional manifest file.  The manifest stores meta-information about
+ * the JAR file contents and is also used for signing JAR files.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * The {@code java.util.jar} package is based on the following
+ * specifications:
+ *
+ * <ul>
+ *   <li><b>Info-ZIP file format</b> - The JAR format is based on the Info-ZIP
+ *       file format. See
+ *       <a href="../zip/package-summary.html#package-description">java.util.zip
+ *       package description.</a> <p>
+ *       In JAR files, all file names must be encoded in the UTF-8 encoding.
+ *   <li><a href="{@docRoot}/../specs/jar/jar.html">
+ *       Manifest and Signature Specification</a> - The manifest format specification.
+ * </ul>
+ *
+ * @since 1.2
+ */
+package java.util.jar;
diff --git a/android-35/java/util/logging/ConsoleHandler.java b/android-35/java/util/logging/ConsoleHandler.java
new file mode 100644
index 0000000..b791547
--- /dev/null
+++ b/android-35/java/util/logging/ConsoleHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
+ * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>ConsoleHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where {@code <handler-name>}
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code ConsoleHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.ConsoleHandler.level=INFO </li>
+ * <li>   java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+public class ConsoleHandler extends StreamHandler {
+    // Private method to configure a ConsoleHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>ConsoleHandler</tt> for <tt>System.err</tt>.
+     * <p>
+     * The <tt>ConsoleHandler</tt> is configured based on
+     * <tt>LogManager</tt> properties (or their default values).
+     *
+     */
+    public ConsoleHandler() {
+        sealed = false;
+        configure();
+        setOutputStream(System.err);
+        sealed = true;
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public void publish(LogRecord record) {
+        super.publish(record);
+        flush();
+    }
+
+    /**
+     * Override <tt>StreamHandler.close</tt> to do a flush but not
+     * to close the output stream.  That is, we do <b>not</b>
+     * close <tt>System.err</tt>.
+     */
+    @Override
+    public void close() {
+        flush();
+    }
+}
diff --git a/android-35/java/util/logging/ErrorManager.java b/android-35/java/util/logging/ErrorManager.java
new file mode 100644
index 0000000..1aaba4c
--- /dev/null
+++ b/android-35/java/util/logging/ErrorManager.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * ErrorManager objects can be attached to Handlers to process
+ * any error that occurs on a Handler during Logging.
+ * <p>
+ * When processing logging output, if a Handler encounters problems
+ * then rather than throwing an Exception back to the issuer of
+ * the logging call (who is unlikely to be interested) the Handler
+ * should call its associated ErrorManager.
+ */
+
+public class ErrorManager {
+   private boolean reported = false;
+
+    /*
+     * We declare standard error codes for important categories of errors.
+     */
+
+    /**
+     * GENERIC_FAILURE is used for failure that don't fit
+     * into one of the other categories.
+     */
+    public final static int GENERIC_FAILURE = 0;
+    /**
+     * WRITE_FAILURE is used when a write to an output stream fails.
+     */
+    public final static int WRITE_FAILURE = 1;
+    /**
+     * FLUSH_FAILURE is used when a flush to an output stream fails.
+     */
+    public final static int FLUSH_FAILURE = 2;
+    /**
+     * CLOSE_FAILURE is used when a close of an output stream fails.
+     */
+    public final static int CLOSE_FAILURE = 3;
+    /**
+     * OPEN_FAILURE is used when an open of an output stream fails.
+     */
+    public final static int OPEN_FAILURE = 4;
+    /**
+     * FORMAT_FAILURE is used when formatting fails for any reason.
+     */
+    public final static int FORMAT_FAILURE = 5;
+
+    /**
+     * The error method is called when a Handler failure occurs.
+     * <p>
+     * This method may be overridden in subclasses.  The default
+     * behavior in this base class is that the first call is
+     * reported to System.err, and subsequent calls are ignored.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    public synchronized void error(String msg, Exception ex, int code) {
+        if (reported) {
+            // We only report the first error, to avoid clogging
+            // the screen.
+            return;
+        }
+        reported = true;
+        String text = "java.util.logging.ErrorManager: " + code;
+        if (msg != null) {
+            text = text + ": " + msg;
+        }
+        System.err.println(text);
+        if (ex != null) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/android-35/java/util/logging/FileHandler.java b/android-35/java/util/logging/FileHandler.java
new file mode 100644
index 0000000..24a7c75
--- /dev/null
+++ b/android-35/java/util/logging/FileHandler.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import static java.nio.file.StandardOpenOption.APPEND;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Simple file logging <tt>Handler</tt>.
+ * <p>
+ * The <tt>FileHandler</tt> can either write to a specified file,
+ * or it can write to a rotating set of files.
+ * <p>
+ * For a rotating set of files, as each file reaches a given size
+ * limit, it is closed, rotated out, and a new file opened.
+ * Successively older files are named by adding "0", "1", "2",
+ * etc. into the base filename.
+ * <p>
+ * By default buffering is enabled in the IO libraries but each log
+ * record is flushed out when it is complete.
+ * <p>
+ * By default the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>FileHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>) </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.limit
+ *        specifies an approximate maximum amount to write (in bytes)
+ *        to any one file.  If this is zero, then there is no limit.
+ *        (Defaults to no limit). </li>
+ * <li>   &lt;handler-name&gt;.count
+ *        specifies how many output files to cycle through (defaults to 1). </li>
+ * <li>   &lt;handler-name&gt;.pattern
+ *        specifies a pattern for generating the output file name.  See
+ *        below for details. (Defaults to "%h/java%u.log"). </li>
+ * <li>   &lt;handler-name&gt;.append
+ *        specifies whether the FileHandler should append onto
+ *        any existing files (defaults to false). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code FileHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.FileHandler.level=INFO </li>
+ * <li>   java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * A pattern consists of a string that includes the following special
+ * components that will be replaced at runtime:
+ * <ul>
+ * <li>    "/"    the local pathname separator </li>
+ * <li>     "%t"   the system temporary directory </li>
+ * <li>     "%h"   the value of the "user.home" system property </li>
+ * <li>     "%g"   the generation number to distinguish rotated logs </li>
+ * <li>     "%u"   a unique number to resolve conflicts </li>
+ * <li>     "%%"   translates to a single percent sign "%" </li>
+ * </ul>
+ * If no "%g" field has been specified and the file count is greater
+ * than one, then the generation number will be added to the end of
+ * the generated filename, after a dot.
+ * <p>
+ * Thus for example a pattern of "%t/java%g.log" with a count of 2
+ * would typically cause log files to be written on Solaris to
+ * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
+ * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
+ * <p>
+ * Generation numbers follow the sequence 0, 1, 2, etc.
+ * <p>
+ * Normally the "%u" unique field is set to 0.  However, if the <tt>FileHandler</tt>
+ * tries to open the filename and finds the file is currently in use by
+ * another process it will increment the unique number field and try
+ * again.  This will be repeated until <tt>FileHandler</tt> finds a file name that
+ * is  not currently in use. If there is a conflict and no "%u" field has
+ * been specified, it will be added at the end of the filename after a dot.
+ * (This will be after any automatically added generation number.)
+ * <p>
+ * Thus if three processes were all trying to log to fred%u.%g.txt then
+ * they  might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
+ * the first file in their rotating sequences.
+ * <p>
+ * Note that the use of unique ids to avoid conflicts is only guaranteed
+ * to work reliably when using a local disk file system.
+ *
+ * @since 1.4
+ */
+
+public class FileHandler extends StreamHandler {
+    private MeteredStream meter;
+    private boolean append;
+    private int limit;       // zero => no limit.
+    private int count;
+    private String pattern;
+    private String lockFileName;
+    private FileChannel lockFileChannel;
+    private File files[];
+    private static final int MAX_LOCKS = 100;
+    private static final Set<String> locks = new HashSet<>();
+
+    /**
+     * A metered stream is a subclass of OutputStream that
+     * (a) forwards all its output to a target stream
+     * (b) keeps track of how many bytes have been written
+     */
+    private class MeteredStream extends OutputStream {
+        final OutputStream out;
+        int written;
+
+        MeteredStream(OutputStream out, int written) {
+            this.out = out;
+            this.written = written;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            out.write(b);
+            written++;
+        }
+
+        @Override
+        public void write(byte buff[]) throws IOException {
+            out.write(buff);
+            written += buff.length;
+        }
+
+        @Override
+        public void write(byte buff[], int off, int len) throws IOException {
+            out.write(buff,off,len);
+            written += len;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            out.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            out.close();
+        }
+    }
+
+    private void open(File fname, boolean append) throws IOException {
+        int len = 0;
+        if (append) {
+            len = (int)fname.length();
+        }
+        FileOutputStream fout = new FileOutputStream(fname.toString(), append);
+        BufferedOutputStream bout = new BufferedOutputStream(fout);
+        meter = new MeteredStream(bout, len);
+        setOutputStream(meter);
+    }
+
+    /**
+     * Configure a FileHandler from LogManager properties and/or default values
+     * as specified in the class javadoc.
+     */
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+
+        String cname = getClass().getName();
+
+        pattern = manager.getStringProperty(cname + ".pattern", "%h/java%u.log");
+        limit = manager.getIntProperty(cname + ".limit", 0);
+        if (limit < 0) {
+            limit = 0;
+        }
+        count = manager.getIntProperty(cname + ".count", 1);
+        if (count <= 0) {
+            count = 1;
+        }
+        append = manager.getBooleanProperty(cname + ".append", false);
+        setLevel(manager.getLevelProperty(cname + ".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname + ".filter", null));
+        setFormatter(manager.getFormatterProperty(cname + ".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+
+    /**
+     * Construct a default <tt>FileHandler</tt>.  This will be configured
+     * entirely from <tt>LogManager</tt> properties (or their default values).
+     * <p>
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control"))</tt>.
+     * @exception  NullPointerException if pattern property is an empty String.
+     */
+    public FileHandler() throws IOException, SecurityException {
+        checkPermission();
+        configure();
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, and the file count is set to one.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern) throws IOException, SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename,
+     * with optional append.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, the file count is set to one, and the append
+     * mode is set to the given <tt>append</tt> argument.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, boolean append) throws IOException,
+            SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        this.append = append;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files.  When
+     * (approximately) the given limit has been written to one file,
+     * another file will be opened.  The output will cycle through a set
+     * of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, int limit, int count)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files
+     * with optional append.  When (approximately) the given limit has
+     * been written to one file, another file will be opened.  The
+     * output will cycle through a set of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument, and the append mode is set to the given
+     * <tt>append</tt> argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     *
+     */
+    public FileHandler(String pattern, int limit, int count, boolean append)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        this.append = append;
+        openFiles();
+    }
+
+    private  boolean isParentWritable(Path path) {
+        Path parent = path.getParent();
+        if (parent == null) {
+            parent = path.toAbsolutePath().getParent();
+        }
+        return parent != null && Files.isWritable(parent);
+    }
+
+    /**
+     * Open the set of output files, based on the configured
+     * instance variables.
+     */
+    private void openFiles() throws IOException {
+        LogManager manager = LogManager.getLogManager();
+        manager.checkPermission();
+        if (count < 1) {
+           throw new IllegalArgumentException("file count = " + count);
+        }
+        if (limit < 0) {
+            limit = 0;
+        }
+
+        // We register our own ErrorManager during initialization
+        // so we can record exceptions.
+        InitializationErrorManager em = new InitializationErrorManager();
+        setErrorManager(em);
+
+        // Create a lock file.  This grants us exclusive access
+        // to our set of output files, as long as we are alive.
+        int unique = -1;
+        for (;;) {
+            unique++;
+            if (unique > MAX_LOCKS) {
+                throw new IOException("Couldn't get lock for " + pattern);
+            }
+            // Generate a lock file name from the "unique" int.
+            lockFileName = generate(pattern, 0, unique).toString() + ".lck";
+            // Now try to lock that filename.
+            // Because some systems (e.g., Solaris) can only do file locks
+            // between processes (and not within a process), we first check
+            // if we ourself already have the file locked.
+            synchronized(locks) {
+                if (locks.contains(lockFileName)) {
+                    // We already own this lock, for a different FileHandler
+                    // object.  Try again.
+                    continue;
+                }
+
+                final Path lockFilePath = Paths.get(lockFileName);
+                FileChannel channel = null;
+                int retries = -1;
+                boolean fileCreated = false;
+                while (channel == null && retries++ < 1) {
+                    try {
+                        channel = FileChannel.open(lockFilePath,
+                                CREATE_NEW, WRITE);
+                        fileCreated = true;
+                    } catch (FileAlreadyExistsException ix) {
+                        // This may be a zombie file left over by a previous
+                        // execution. Reuse it - but only if we can actually
+                        // write to its directory.
+                        // Note that this is a situation that may happen,
+                        // but not too frequently.
+                        if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
+                            && isParentWritable(lockFilePath)) {
+                            try {
+                                channel = FileChannel.open(lockFilePath,
+                                    WRITE, APPEND);
+                            } catch (NoSuchFileException x) {
+                                // Race condition - retry once, and if that
+                                // fails again just try the next name in
+                                // the sequence.
+                                continue;
+                            } catch(IOException x) {
+                                // the file may not be writable for us.
+                                // try the next name in the sequence
+                                break;
+                            }
+                        } else {
+                            // at this point channel should still be null.
+                            // break and try the next name in the sequence.
+                            break;
+                        }
+                    }
+                }
+
+                if (channel == null) continue; // try the next name;
+                lockFileChannel = channel;
+
+                boolean available;
+                try {
+                    available = lockFileChannel.tryLock() != null;
+                    // We got the lock OK.
+                    // At this point we could call File.deleteOnExit().
+                    // However, this could have undesirable side effects
+                    // as indicated by JDK-4872014. So we will instead
+                    // rely on the fact that close() will remove the lock
+                    // file and that whoever is creating FileHandlers should
+                    // be responsible for closing them.
+                } catch (IOException ix) {
+                    // We got an IOException while trying to get the lock.
+                    // This normally indicates that locking is not supported
+                    // on the target directory.  We have to proceed without
+                    // getting a lock.   Drop through, but only if we did
+                    // create the file...
+                    available = fileCreated;
+                } catch (OverlappingFileLockException x) {
+                    // someone already locked this file in this VM, through
+                    // some other channel - that is - using something else
+                    // than new FileHandler(...);
+                    // continue searching for an available lock.
+                    available = false;
+                }
+                if (available) {
+                    // We got the lock.  Remember it.
+                    locks.add(lockFileName);
+                    break;
+                }
+
+                // We failed to get the lock.  Try next file.
+                lockFileChannel.close();
+            }
+        }
+
+        files = new File[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = generate(pattern, i, unique);
+        }
+
+        // Create the initial log file.
+        if (append) {
+            open(files[0], true);
+        } else {
+            rotate();
+        }
+
+        // Did we detect any exceptions during initialization?
+        Exception ex = em.lastException;
+        if (ex != null) {
+            if (ex instanceof IOException) {
+                throw (IOException) ex;
+            } else if (ex instanceof SecurityException) {
+                throw (SecurityException) ex;
+            } else {
+                throw new IOException("Exception: " + ex);
+            }
+        }
+
+        // Install the normal default ErrorManager.
+        setErrorManager(new ErrorManager());
+    }
+
+    /**
+     * Generate a file based on a user-supplied pattern, generation number,
+     * and an integer uniqueness suffix
+     * @param pattern the pattern for naming the output file
+     * @param generation the generation number to distinguish rotated logs
+     * @param unique a unique number to resolve conflicts
+     * @return the generated File
+     * @throws IOException
+     */
+    private File generate(String pattern, int generation, int unique)
+            throws IOException {
+        File file = null;
+        String word = "";
+        int ix = 0;
+        boolean sawg = false;
+        boolean sawu = false;
+        while (ix < pattern.length()) {
+            char ch = pattern.charAt(ix);
+            ix++;
+            char ch2 = 0;
+            if (ix < pattern.length()) {
+                ch2 = Character.toLowerCase(pattern.charAt(ix));
+            }
+            if (ch == '/') {
+                if (file == null) {
+                    file = new File(word);
+                } else {
+                    file = new File(file, word);
+                }
+                word = "";
+                continue;
+            } else  if (ch == '%') {
+                if (ch2 == 't') {
+                    String tmpDir = System.getProperty("java.io.tmpdir");
+                    if (tmpDir == null) {
+                        tmpDir = System.getProperty("user.home");
+                    }
+                    file = new File(tmpDir);
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'h') {
+                    file = new File(System.getProperty("user.home"));
+                    // Android-removed: Don't prohibit using user.home property in setuid programs.
+                    /*
+                    if (isSetUID()) {
+                        // Ok, we are in a set UID program.  For safety's sake
+                        // we disallow attempts to open files relative to %h.
+                        throw new IOException("can't use %h in set UID program");
+                    }
+                    */
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'g') {
+                    word = word + generation;
+                    sawg = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == 'u') {
+                    word = word + unique;
+                    sawu = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == '%') {
+                    word = word + "%";
+                    ix++;
+                    continue;
+                }
+            }
+            word = word + ch;
+        }
+        if (count > 1 && !sawg) {
+            word = word + "." + generation;
+        }
+        if (unique > 0 && !sawu) {
+            word = word + "." + unique;
+        }
+        if (word.length() > 0) {
+            if (file == null) {
+                file = new File(word);
+            } else {
+                file = new File(file, word);
+            }
+        }
+        return file;
+    }
+
+    /**
+     * Rotate the set of output files
+     */
+    private synchronized void rotate() {
+        Level oldLevel = getLevel();
+        setLevel(Level.OFF);
+
+        super.close();
+        for (int i = count-2; i >= 0; i--) {
+            File f1 = files[i];
+            File f2 = files[i+1];
+            if (f1.exists()) {
+                if (f2.exists()) {
+                    f2.delete();
+                }
+                f1.renameTo(f2);
+            }
+        }
+        try {
+            open(files[0], false);
+        } catch (IOException ix) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ix, ErrorManager.OPEN_FAILURE);
+
+        }
+        setLevel(oldLevel);
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+        if (limit > 0 && meter.written >= limit) {
+            // We performed access checks in the "init" method to make sure
+            // we are only initialized from trusted code.  So we assume
+            // it is OK to write the target files, even if we are
+            // currently being called from untrusted code.
+            // So it is safe to raise privilege here.
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
+                public Object run() {
+                    rotate();
+                    return null;
+                }
+            });
+        }
+    }
+
+    /**
+     * Close all the files.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        // Unlock any lock file.
+        if (lockFileName == null) {
+            return;
+        }
+        try {
+            // Close the lock file channel (which also will free any locks)
+            lockFileChannel.close();
+        } catch (Exception ex) {
+            // Problems closing the stream.  Punt.
+        }
+        synchronized(locks) {
+            locks.remove(lockFileName);
+        }
+        new File(lockFileName).delete();
+        lockFileName = null;
+        lockFileChannel = null;
+    }
+
+    private static class InitializationErrorManager extends ErrorManager {
+        Exception lastException;
+        @Override
+        public void error(String msg, Exception ex, int code) {
+            lastException = ex;
+        }
+    }
+
+    // Android-removed: isSetUID's only caller is removed.
+    /*
+    /**
+     * check if we are in a set UID program.
+     *
+    private static native boolean isSetUID();
+    */
+}
diff --git a/android-35/java/util/logging/Filter.java b/android-35/java/util/logging/Filter.java
new file mode 100644
index 0000000..4383707
--- /dev/null
+++ b/android-35/java/util/logging/Filter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Filter can be used to provide fine grain control over
+ * what is logged, beyond the control provided by log levels.
+ * <p>
+ * Each Logger and each Handler can have a filter associated with it.
+ * The Logger or Handler will call the isLoggable method to check
+ * if a given LogRecord should be published.  If isLoggable returns
+ * false, the LogRecord will be discarded.
+ *
+ * @since 1.4
+ */
+@FunctionalInterface
+public interface Filter {
+
+    /**
+     * Check if a given log record should be published.
+     * @param record  a LogRecord
+     * @return true if the log record should be published.
+     */
+    public boolean isLoggable(LogRecord record);
+}
diff --git a/android-35/java/util/logging/Formatter.java b/android-35/java/util/logging/Formatter.java
new file mode 100644
index 0000000..19e079f
--- /dev/null
+++ b/android-35/java/util/logging/Formatter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Formatter provides support for formatting LogRecords.
+ * <p>
+ * Typically each logging Handler will have a Formatter associated
+ * with it.  The Formatter takes a LogRecord and converts it to
+ * a string.
+ * <p>
+ * Some formatters (such as the XMLFormatter) need to wrap head
+ * and tail strings around a set of formatted records. The getHeader
+ * and getTail methods can be used to obtain these strings.
+ *
+ * @since 1.4
+ */
+
+public abstract class Formatter {
+
+    /**
+     * Construct a new formatter.
+     */
+    protected Formatter() {
+    }
+
+    /**
+     * Format the given log record and return the formatted string.
+     * <p>
+     * The resulting formatted String will normally include a
+     * localized and formatted version of the LogRecord's message field.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return the formatted log record
+     */
+    public abstract String format(LogRecord record);
+
+
+    /**
+     * Return the header string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  header string
+     */
+    public String getHead(Handler h) {
+        return "";
+    }
+
+    /**
+     * Return the tail string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  tail string
+     */
+    public String getTail(Handler h) {
+        return "";
+    }
+
+
+    /**
+     * Localize and format the message string from a log record.  This
+     * method is provided as a convenience for Formatter subclasses to
+     * use when they are performing formatting.
+     * <p>
+     * The message string is first localized to a format string using
+     * the record's ResourceBundle.  (If there is no ResourceBundle,
+     * or if the message key is not found, then the key is used as the
+     * format string.)  The format String uses java.text style
+     * formatting.
+     * <ul>
+     * <li>If there are no parameters, no formatter is used.
+     * <li>Otherwise, if the string contains "{0" then
+     *     java.text.MessageFormat  is used to format the string.
+     * <li>Otherwise no formatting is performed.
+     * </ul>
+     * <p>
+     *
+     * @param  record  the log record containing the raw message
+     * @return   a localized and formatted message
+     */
+    public synchronized String formatMessage(LogRecord record) {
+        String format = record.getMessage();
+        java.util.ResourceBundle catalog = record.getResourceBundle();
+        if (catalog != null) {
+            try {
+                format = catalog.getString(record.getMessage());
+            } catch (java.util.MissingResourceException ex) {
+                // Drop through.  Use record message as format
+                format = record.getMessage();
+            }
+        }
+        // Do the formatting.
+        try {
+            Object parameters[] = record.getParameters();
+            if (parameters == null || parameters.length == 0) {
+                // No parameters.  Just return format string.
+                return format;
+            }
+            // Is it a java.text style format?
+            // Ideally we could match with
+            // Pattern.compile("\\{\\d").matcher(format).find())
+            // However the cost is 14% higher, so we cheaply check for
+            // 1 of the first 4 parameters
+            if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
+                        format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
+                return java.text.MessageFormat.format(format, parameters);
+            }
+            return format;
+
+        } catch (Exception ex) {
+            // Formatting failed: use localized format string.
+            return format;
+        }
+    }
+}
diff --git a/android-35/java/util/logging/Handler.java b/android-35/java/util/logging/Handler.java
new file mode 100644
index 0000000..1cc7b43
--- /dev/null
+++ b/android-35/java/util/logging/Handler.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.UnsupportedEncodingException;
+/**
+ * A <tt>Handler</tt> object takes log messages from a <tt>Logger</tt> and
+ * exports them.  It might for example, write them to a console
+ * or write them to a file, or send them to a network logging service,
+ * or forward them to an OS log, or whatever.
+ * <p>
+ * A <tt>Handler</tt> can be disabled by doing a <tt>setLevel(Level.OFF)</tt>
+ * and can  be re-enabled by doing a <tt>setLevel</tt> with an appropriate level.
+ * <p>
+ * <tt>Handler</tt> classes typically use <tt>LogManager</tt> properties to set
+ * default values for the <tt>Handler</tt>'s <tt>Filter</tt>, <tt>Formatter</tt>,
+ * and <tt>Level</tt>.  See the specific documentation for each concrete
+ * <tt>Handler</tt> class.
+ *
+ *
+ * @since 1.4
+ */
+
+public abstract class Handler {
+    private static final int offValue = Level.OFF.intValue();
+    private final LogManager manager = LogManager.getLogManager();
+
+    // We're using volatile here to avoid synchronizing getters, which
+    // would prevent other threads from calling isLoggable()
+    // while publish() is executing.
+    // On the other hand, setters will be synchronized to exclude concurrent
+    // execution with more complex methods, such as StreamHandler.publish().
+    // We wouldn't want 'level' to be changed by another thread in the middle
+    // of the execution of a 'publish' call.
+    private volatile Filter filter;
+    private volatile Formatter formatter;
+    private volatile Level logLevel = Level.ALL;
+    private volatile ErrorManager errorManager = new ErrorManager();
+    private volatile String encoding;
+
+    // Package private support for security checking.  When sealed
+    // is true, we access check updates to the class.
+    boolean sealed = true;
+
+    /**
+     * Default constructor.  The resulting <tt>Handler</tt> has a log
+     * level of <tt>Level.ALL</tt>, no <tt>Formatter</tt>, and no
+     * <tt>Filter</tt>.  A default <tt>ErrorManager</tt> instance is installed
+     * as the <tt>ErrorManager</tt>.
+     */
+    protected Handler() {
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * The <tt>Handler</tt>  is responsible for formatting the message, when and
+     * if necessary.  The formatting should include localization.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    public abstract void publish(LogRecord record);
+
+    /**
+     * Flush any buffered output.
+     */
+    public abstract void flush();
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * <p>
+     * The close method will perform a <tt>flush</tt> and then close the
+     * <tt>Handler</tt>.   After close has been called this <tt>Handler</tt>
+     * should no longer be used.  Method calls may either be silently
+     * ignored or may throw runtime exceptions.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public abstract void close() throws SecurityException;
+
+    /**
+     * Set a <tt>Formatter</tt>.  This <tt>Formatter</tt> will be used
+     * to format <tt>LogRecords</tt> for this <tt>Handler</tt>.
+     * <p>
+     * Some <tt>Handlers</tt> may not use <tt>Formatters</tt>, in
+     * which case the <tt>Formatter</tt> will be remembered, but not used.
+     * <p>
+     * @param newFormatter the <tt>Formatter</tt> to use (may not be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
+        checkPermission();
+        // Check for a null pointer:
+        newFormatter.getClass();
+        formatter = newFormatter;
+    }
+
+    /**
+     * Return the <tt>Formatter</tt> for this <tt>Handler</tt>.
+     * @return the <tt>Formatter</tt> (may be null).
+     */
+    public Formatter getFormatter() {
+        return formatter;
+    }
+
+    /**
+     * Set the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        checkPermission();
+        if (encoding != null) {
+            try {
+                if(!java.nio.charset.Charset.isSupported(encoding)) {
+                    throw new UnsupportedEncodingException(encoding);
+                }
+            } catch (java.nio.charset.IllegalCharsetNameException e) {
+                throw new UnsupportedEncodingException(encoding);
+            }
+        }
+        this.encoding = encoding;
+    }
+
+    /**
+     * Return the character encoding for this <tt>Handler</tt>.
+     *
+     * @return  The encoding name.  May be null, which indicates the
+     *          default encoding should be used.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Set a <tt>Filter</tt> to control output on this <tt>Handler</tt>.
+     * <P>
+     * For each call of <tt>publish</tt> the <tt>Handler</tt> will call
+     * this <tt>Filter</tt> (if it is non-null) to check if the
+     * <tt>LogRecord</tt> should be published or discarded.
+     *
+     * @param   newFilter  a <tt>Filter</tt> object (may be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current <tt>Filter</tt> for this <tt>Handler</tt>.
+     *
+     * @return  a <tt>Filter</tt> object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Define an ErrorManager for this Handler.
+     * <p>
+     * The ErrorManager's "error" method will be invoked if any
+     * errors occur while using this Handler.
+     *
+     * @param em  the new ErrorManager
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setErrorManager(ErrorManager em) {
+        checkPermission();
+        if (em == null) {
+           throw new NullPointerException();
+        }
+        errorManager = em;
+    }
+
+    /**
+     * Retrieves the ErrorManager for this Handler.
+     *
+     * @return the ErrorManager for this Handler
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public ErrorManager getErrorManager() {
+        checkPermission();
+        return errorManager;
+    }
+
+   /**
+     * Protected convenience method to report an error to this Handler's
+     * ErrorManager.  Note that this method retrieves and uses the ErrorManager
+     * without doing a security check.  It can therefore be used in
+     * environments where the caller may be non-privileged.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    protected void reportError(String msg, Exception ex, int code) {
+        try {
+            errorManager.error(msg, ex, code);
+        } catch (Exception ex2) {
+            System.err.println("Handler.reportError caught:");
+            ex2.printStackTrace();
+        }
+    }
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this <tt>Handler</tt>.  Message levels lower than this
+     * value will be discarded.
+     * <p>
+     * The intention is to allow developers to turn on voluminous
+     * logging, but to limit the messages that are sent to certain
+     * <tt>Handlers</tt>.
+     *
+     * @param newLevel   the new value for the log level
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        logLevel = newLevel;
+    }
+
+    /**
+     * Get the log level specifying which messages will be
+     * logged by this <tt>Handler</tt>.  Message levels lower
+     * than this level will be discarded.
+     * @return  the level of messages being logged.
+     */
+    public Level getLevel() {
+        return logLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate
+     * <tt>Level</tt> and  whether it satisfies any <tt>Filter</tt>.  It also
+     * may make other <tt>Handler</tt> specific checks that might prevent a
+     * handler from logging the <tt>LogRecord</tt>. It will return false if
+     * the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    public boolean isLoggable(LogRecord record) {
+        final int levelValue = getLevel().intValue();
+        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        final Filter filter = getFilter();
+        if (filter == null) {
+            return true;
+        }
+        return filter.isLoggable(record);
+    }
+
+    // Package-private support method for security checks.
+    // If "sealed" is true, we check that the caller has
+    // appropriate security privileges to update Handler
+    // state and if not throw a SecurityException.
+    void checkPermission() throws SecurityException {
+        if (sealed) {
+            manager.checkPermission();
+        }
+    }
+}
diff --git a/android-35/java/util/logging/Level.java b/android-35/java/util/logging/Level.java
new file mode 100644
index 0000000..17b585b
--- /dev/null
+++ b/android-35/java/util/logging/Level.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * The Level class defines a set of standard logging levels that
+ * can be used to control logging output.  The logging Level objects
+ * are ordered and are specified by ordered integers.  Enabling logging
+ * at a given level also enables logging at all higher levels.
+ * <p>
+ * Clients should normally use the predefined Level constants such
+ * as Level.SEVERE.
+ * <p>
+ * The levels in descending order are:
+ * <ul>
+ * <li>SEVERE (highest value)
+ * <li>WARNING
+ * <li>INFO
+ * <li>CONFIG
+ * <li>FINE
+ * <li>FINER
+ * <li>FINEST  (lowest value)
+ * </ul>
+ * In addition there is a level OFF that can be used to turn
+ * off logging, and a level ALL that can be used to enable
+ * logging of all messages.
+ * <p>
+ * It is possible for third parties to define additional logging
+ * levels by subclassing Level.  In such cases subclasses should
+ * take care to chose unique integer level values and to ensure that
+ * they maintain the Object uniqueness property across serialization
+ * by defining a suitable readResolve method.
+ *
+ * @since 1.4
+ */
+
+public class Level implements java.io.Serializable {
+    private static final String defaultBundle = "sun.util.logging.resources.logging";
+
+    /**
+     * @serial  The non-localized name of the level.
+     */
+    private final String name;
+
+    /**
+     * @serial  The integer value of the level.
+     */
+    private final int value;
+
+    /**
+     * @serial The resource bundle name to be used in localizing the level name.
+     */
+    private final String resourceBundleName;
+
+    // localized level name
+    private transient String localizedLevelName;
+    private transient Locale cachedLocale;
+
+    /**
+     * OFF is a special level that can be used to turn off logging.
+     * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
+     */
+    public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
+
+    /**
+     * SEVERE is a message level indicating a serious failure.
+     * <p>
+     * In general SEVERE messages should describe events that are
+     * of considerable importance and which will prevent normal
+     * program execution.   They should be reasonably intelligible
+     * to end users and to system administrators.
+     * This level is initialized to <CODE>1000</CODE>.
+     */
+    public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
+
+    /**
+     * WARNING is a message level indicating a potential problem.
+     * <p>
+     * In general WARNING messages should describe events that will
+     * be of interest to end users or system managers, or which
+     * indicate potential problems.
+     * This level is initialized to <CODE>900</CODE>.
+     */
+    public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
+
+    /**
+     * INFO is a message level for informational messages.
+     * <p>
+     * Typically INFO messages will be written to the console
+     * or its equivalent.  So the INFO level should only be
+     * used for reasonably significant messages that will
+     * make sense to end users and system administrators.
+     * This level is initialized to <CODE>800</CODE>.
+     */
+    public static final Level INFO = new Level("INFO", 800, defaultBundle);
+
+    /**
+     * CONFIG is a message level for static configuration messages.
+     * <p>
+     * CONFIG messages are intended to provide a variety of static
+     * configuration information, to assist in debugging problems
+     * that may be associated with particular configurations.
+     * For example, CONFIG message might include the CPU type,
+     * the graphics depth, the GUI look-and-feel, etc.
+     * This level is initialized to <CODE>700</CODE>.
+     */
+    public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
+
+    /**
+     * FINE is a message level providing tracing information.
+     * <p>
+     * All of FINE, FINER, and FINEST are intended for relatively
+     * detailed tracing.  The exact meaning of the three levels will
+     * vary between subsystems, but in general, FINEST should be used
+     * for the most voluminous detailed output, FINER for somewhat
+     * less detailed output, and FINE for the  lowest volume (and
+     * most important) messages.
+     * <p>
+     * In general the FINE level should be used for information
+     * that will be broadly interesting to developers who do not have
+     * a specialized interest in the specific subsystem.
+     * <p>
+     * FINE messages might include things like minor (recoverable)
+     * failures.  Issues indicating potential performance problems
+     * are also worth logging as FINE.
+     * This level is initialized to <CODE>500</CODE>.
+     */
+    public static final Level FINE = new Level("FINE", 500, defaultBundle);
+
+    /**
+     * FINER indicates a fairly detailed tracing message.
+     * By default logging calls for entering, returning, or throwing
+     * an exception are traced at this level.
+     * This level is initialized to <CODE>400</CODE>.
+     */
+    public static final Level FINER = new Level("FINER", 400, defaultBundle);
+
+    /**
+     * FINEST indicates a highly detailed tracing message.
+     * This level is initialized to <CODE>300</CODE>.
+     */
+    public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
+
+    /**
+     * ALL indicates that all messages should be logged.
+     * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
+     */
+    public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
+
+    /**
+     * Create a named Level with a given integer value.
+     * <p>
+     * Note that this constructor is "protected" to allow subclassing.
+     * In general clients of logging should use one of the constant Level
+     * objects such as SEVERE or FINEST.  However, if clients need to
+     * add new logging levels, they may subclass Level and define new
+     * constants.
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value) {
+        this(name, value, null);
+    }
+
+    /**
+     * Create a named Level with a given integer value and a
+     * given localization resource name.
+     * <p>
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @param resourceBundleName name of a resource bundle to use in
+     *    localizing the given name. If the resourceBundleName is null
+     *    or an empty string, it is ignored.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value, String resourceBundleName) {
+        this(name, value, resourceBundleName, true);
+    }
+
+    // private constructor to specify whether this instance should be added
+    // to the KnownLevel list from which Level.parse method does its look up
+    private Level(String name, int value, String resourceBundleName, boolean visible) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.value = value;
+        this.resourceBundleName = resourceBundleName;
+        this.localizedLevelName = resourceBundleName == null ? name : null;
+        this.cachedLocale = null;
+        if (visible) {
+            KnownLevel.add(this);
+        }
+    }
+
+    /**
+     * Return the level's localization resource bundle name, or
+     * null if no localization bundle is defined.
+     *
+     * @return localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Return the non-localized string name of the Level.
+     *
+     * @return non-localized name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return the localized string name of the Level, for
+     * the current default locale.
+     * <p>
+     * If no localization information is available, the
+     * non-localized name is returned.
+     *
+     * @return localized name
+     */
+    public String getLocalizedName() {
+        return getLocalizedLevelName();
+    }
+
+    // package-private getLevelName() is used by the implementation
+    // instead of getName() to avoid calling the subclass's version
+    final String getLevelName() {
+        return this.name;
+    }
+
+    private String computeLocalizedLevelName(Locale newLocale) {
+        // Android-changed: Use Thread.currentThread().getContextClassLoader().
+        // Otherwise, we might get a BootClassLoader.
+        // ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale,
+                                                     Thread.currentThread().getContextClassLoader());
+        final String localizedName = rb.getString(name);
+
+        final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
+        if (!isDefaultBundle) return localizedName;
+
+        // This is a trick to determine whether the name has been translated
+        // or not. If it has not been translated, we need to use Locale.ROOT
+        // when calling toUpperCase().
+        final Locale rbLocale = rb.getLocale();
+        final Locale locale =
+                Locale.ROOT.equals(rbLocale)
+                || name.equals(localizedName.toUpperCase(Locale.ROOT))
+                ? Locale.ROOT : rbLocale;
+
+        // ALL CAPS in a resource bundle's message indicates no translation
+        // needed per Oracle translation guideline.  To workaround this
+        // in Oracle JDK implementation, convert the localized level name
+        // to uppercase for compatibility reason.
+        return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
+    }
+
+    // Avoid looking up the localizedLevelName twice if we already
+    // have it.
+    final String getCachedLocalizedLevelName() {
+
+        if (localizedLevelName != null) {
+            if (cachedLocale != null) {
+                if (cachedLocale.equals(Locale.getDefault())) {
+                    // OK: our cached value was looked up with the same
+                    //     locale. We can use it.
+                    return localizedLevelName;
+                }
+            }
+        }
+
+        if (resourceBundleName == null) {
+            // No resource bundle: just use the name.
+            return name;
+        }
+
+        // We need to compute the localized name.
+        // Either because it's the first time, or because our cached
+        // value is for a different locale. Just return null.
+        return null;
+    }
+
+    final synchronized String getLocalizedLevelName() {
+
+        // See if we have a cached localized name
+        final String cachedLocalizedName = getCachedLocalizedLevelName();
+        if (cachedLocalizedName != null) {
+            return cachedLocalizedName;
+        }
+
+        // No cached localized name or cache invalid.
+        // Need to compute the localized name.
+        final Locale newLocale = Locale.getDefault();
+        try {
+            localizedLevelName = computeLocalizedLevelName(newLocale);
+        } catch (Exception ex) {
+            localizedLevelName = name;
+        }
+        cachedLocale = newLocale;
+        return localizedLevelName;
+    }
+
+    // Returns a mirrored Level object that matches the given name as
+    // specified in the Level.parse method.  Returns null if not found.
+    //
+    // It returns the same Level object as the one returned by Level.parse
+    // method if the given name is a non-localized name or integer.
+    //
+    // If the name is a localized name, findLevel and parse method may
+    // return a different level value if there is a custom Level subclass
+    // that overrides Level.getLocalizedName() to return a different string
+    // than what's returned by the default implementation.
+    //
+    static Level findLevel(String name) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.mirroredLevel;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this Level.
+     *
+     * @return the non-localized name of the Level, for example "INFO".
+     */
+    @Override
+    public final String toString() {
+        return name;
+    }
+
+    /**
+     * Get the integer value for this level.  This integer value
+     * can be used for efficient ordering comparisons between
+     * Level objects.
+     * @return the integer value for this level.
+     */
+    public final int intValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = -8176160795706313070L;
+
+    // Serialization magic to prevent "doppelgangers".
+    // This is a performance optimization.
+    private Object readResolve() {
+        KnownLevel o = KnownLevel.matches(this);
+        if (o != null) {
+            return o.levelObject;
+        }
+
+        // Woops.  Whoever sent us this object knows
+        // about a new log level.  Add it to our list.
+        Level level = new Level(this.name, this.value, this.resourceBundleName);
+        return level;
+    }
+
+    /**
+     * Parse a level name string into a Level.
+     * <p>
+     * The argument string may consist of either a level name
+     * or an integer value.
+     * <p>
+     * For example:
+     * <ul>
+     * <li>     "SEVERE"
+     * <li>     "1000"
+     * </ul>
+     *
+     * @param  name   string to be parsed
+     * @throws NullPointerException if the name is null
+     * @throws IllegalArgumentException if the value is not valid.
+     * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
+     * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
+     * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
+     * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
+     * appropriate package access, or new levels defined or created
+     * by subclasses.
+     *
+     * @return The parsed value. Passing an integer that corresponds to a known name
+     * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
+     * Passing an integer that does not (e.g., 1) will return a new level name
+     * initialized to that value.
+     */
+    public static synchronized Level parse(String name) throws IllegalArgumentException {
+        // Check that name is not null.
+        name.length();
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.levelObject;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        // Finally, look for a known level with the given localized name,
+        // in the current default locale.
+        // This is relatively expensive, but not excessively so.
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // OK, we've tried everything and failed
+        throw new IllegalArgumentException("Bad level \"" + name + "\"");
+    }
+
+    /**
+     * Compare two objects for value equality.
+     * @return true if and only if the two objects have the same level value.
+     */
+    @Override
+    public boolean equals(Object ox) {
+        try {
+            Level lx = (Level)ox;
+            return (lx.value == this.value);
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * Generate a hashcode.
+     * @return a hashcode based on the level value
+     */
+    @Override
+    public int hashCode() {
+        return this.value;
+    }
+
+    // KnownLevel class maintains the global list of all known levels.
+    // The API allows multiple custom Level instances of the same name/value
+    // be created. This class provides convenient methods to find a level
+    // by a given name, by a given value, or by a given localized name.
+    //
+    // KnownLevel wraps the following Level objects:
+    // 1. levelObject:   standard Level object or custom Level object
+    // 2. mirroredLevel: Level object representing the level specified in the
+    //                   logging configuration.
+    //
+    // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // are non-final but the name and resource bundle name are parameters to
+    // the Level constructor.  Use the mirroredLevel object instead of the
+    // levelObject to prevent the logging framework to execute foreign code
+    // implemented by untrusted Level subclass.
+    //
+    // Implementation Notes:
+    // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // were final, the following KnownLevel implementation can be removed.
+    // Future API change should take this into consideration.
+    static final class KnownLevel {
+        private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
+        private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
+        final Level levelObject;     // instance of Level class or Level subclass
+        final Level mirroredLevel;   // mirror of the custom Level
+        KnownLevel(Level l) {
+            this.levelObject = l;
+            if (l.getClass() == Level.class) {
+                this.mirroredLevel = l;
+            } else {
+                // this mirrored level object is hidden
+                this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
+            }
+        }
+
+        static synchronized void add(Level l) {
+            // the mirroredLevel object is always added to the list
+            // before the custom Level instance
+            KnownLevel o = new KnownLevel(l);
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list == null) {
+                list = new ArrayList<>();
+                nameToLevels.put(l.name, list);
+            }
+            list.add(o);
+
+            list = intToLevels.get(l.value);
+            if (list == null) {
+                list = new ArrayList<>();
+                intToLevels.put(l.value, list);
+            }
+            list.add(o);
+        }
+
+        // Returns a KnownLevel with the given non-localized name.
+        static synchronized KnownLevel findByName(String name) {
+            List<KnownLevel> list = nameToLevels.get(name);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given value.
+        static synchronized KnownLevel findByValue(int value) {
+            List<KnownLevel> list = intToLevels.get(value);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given localized name matching
+        // by calling the Level.getLocalizedLevelName() method (i.e. found
+        // from the resourceBundle associated with the Level object).
+        // This method does not call Level.getLocalizedName() that may
+        // be overridden in a subclass implementation
+        static synchronized KnownLevel findByLocalizedLevelName(String name) {
+            for (List<KnownLevel> levels : nameToLevels.values()) {
+                for (KnownLevel l : levels) {
+                    String lname = l.levelObject.getLocalizedLevelName();
+                    if (name.equals(lname)) {
+                        return l;
+                    }
+                }
+            }
+            return null;
+        }
+
+        static synchronized KnownLevel matches(Level l) {
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list != null) {
+                for (KnownLevel level : list) {
+                    Level other = level.mirroredLevel;
+                    Class<? extends Level> type = level.levelObject.getClass();
+                    if (l.value == other.value &&
+                           (l.resourceBundleName == other.resourceBundleName ||
+                               (l.resourceBundleName != null &&
+                                l.resourceBundleName.equals(other.resourceBundleName)))) {
+                        if (type == l.getClass()) {
+                            return level;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/android-35/java/util/logging/LogManager.java b/android-35/java/util/logging/LogManager.java
new file mode 100644
index 0000000..e8f9027
--- /dev/null
+++ b/android-35/java/util/logging/LogManager.java
@@ -0,0 +1,1831 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.beans.PropertyChangeListener;
+
+/**
+ * There is a single global LogManager object that is used to
+ * maintain a set of shared state about Loggers and log services.
+ * <p>
+ * This LogManager object:
+ * <ul>
+ * <li> Manages a hierarchical namespace of Logger objects.  All
+ *      named Loggers are stored in this namespace.
+ * <li> Manages a set of logging control properties.  These are
+ *      simple key-value pairs that can be used by Handlers and
+ *      other logging objects to configure themselves.
+ * </ul>
+ * <p>
+ * The global LogManager object can be retrieved using LogManager.getLogManager().
+ * The LogManager object is created during class initialization and
+ * cannot subsequently be changed.
+ * <p>
+ * At startup the LogManager class is located using the
+ * java.util.logging.manager system property.
+ * <p>
+ * The LogManager defines two optional system properties that allow control over
+ * the initial configuration:
+ * <ul>
+ * <li>"java.util.logging.config.class"
+ * <li>"java.util.logging.config.file"
+ * </ul>
+ * These two properties may be specified on the command line to the "java"
+ * command, or as system property definitions passed to JNI_CreateJavaVM.
+ * <p>
+ * If the "java.util.logging.config.class" property is set, then the
+ * property value is treated as a class name.  The given class will be
+ * loaded, an object will be instantiated, and that object's constructor
+ * is responsible for reading in the initial configuration.  (That object
+ * may use other system properties to control its configuration.)  The
+ * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
+ * to define properties in the LogManager.
+ * <p>
+ * If "java.util.logging.config.class" property is <b>not</b> set,
+ * then the "java.util.logging.config.file" system property can be used
+ * to specify a properties file (in java.util.Properties format). The
+ * initial logging configuration will be read from this file.
+ * <p>
+ * If neither of these properties is defined then the LogManager uses its
+ * default configuration. The default configuration is typically loaded from the
+ * properties file "{@code lib/logging.properties}" in the Java installation
+ * directory.
+ * <p>
+ * The properties for loggers and Handlers will have names starting
+ * with the dot-separated name for the handler or logger.
+ * <p>
+ * The global logging properties may include:
+ * <ul>
+ * <li>A property "handlers".  This defines a whitespace or comma separated
+ * list of class names for handler classes to load and register as
+ * handlers on the root Logger (the Logger named "").  Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
+ * comma separated list of class names for handlers classes to
+ * load and register as handlers to the specified logger. Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
+ * value. By default every logger calls its parent in addition to
+ * handling the logging message itself, this often result in messages
+ * being handled by the root logger as well. When setting this property
+ * to false a Handler needs to be configured for this logger otherwise
+ * no logging messages are delivered.
+ *
+ * <li>A property "config".  This property is intended to allow
+ * arbitrary configuration code to be run.  The property defines a
+ * whitespace or comma separated list of class names.  A new instance will be
+ * created for each named class.  The default constructor of each class
+ * may execute arbitrary code to update the logging configuration, such as
+ * setting logger levels, adding handlers, adding filters, etc.
+ * </ul>
+ * <p>
+ * Note that all classes loaded during LogManager configuration are
+ * first searched on the system class path before any user class path.
+ * That includes the LogManager class, any config classes, and any
+ * handler classes.
+ * <p>
+ * Loggers are organized into a naming hierarchy based on their
+ * dot separated names.  Thus "a.b.c" is a child of "a.b", but
+ * "a.b1" and a.b2" are peers.
+ * <p>
+ * All properties whose names end with ".level" are assumed to define
+ * log levels for Loggers.  Thus "foo.level" defines a log level for
+ * the logger called "foo" and (recursively) for any of its children
+ * in the naming hierarchy.  Log Levels are applied in the order they
+ * are defined in the properties file.  Thus level settings for child
+ * nodes in the tree should come after settings for their parents.
+ * The property name ".level" can be used to set the level for the
+ * root of the tree.
+ * <p>
+ * All methods on the LogManager object are multi-thread safe.
+ *
+ * @since 1.4
+*/
+
+public class LogManager {
+    // The global LogManager object
+    private static final LogManager manager;
+
+    // 'props' is assigned within a lock but accessed without it.
+    // Declaring it volatile makes sure that another thread will not
+    // be able to see a partially constructed 'props' object.
+    // (seeing a partially constructed 'props' object can result in
+    // NPE being thrown in Hashtable.get(), because it leaves the door
+    // open for props.getProperties() to be called before the construcor
+    // of Hashtable is actually completed).
+    private volatile Properties props = new Properties();
+    private final static Level defaultLevel = Level.INFO;
+
+    // The map of the registered listeners. The map value is the registration
+    // count to allow for cases where the same listener is registered many times.
+    private final Map<Object,Integer> listenerMap = new HashMap<>();
+
+    // LoggerContext for system loggers and user loggers
+    private final LoggerContext systemContext = new SystemLoggerContext();
+    private final LoggerContext userContext = new LoggerContext();
+    // non final field - make it volatile to make sure that other threads
+    // will see the new value once ensureLogManagerInitialized() has finished
+    // executing.
+    private volatile Logger rootLogger;
+    // Have we done the primordial reading of the configuration file?
+    // (Must be done after a suitable amount of java.lang.System
+    // initialization has been done)
+    private volatile boolean readPrimordialConfiguration;
+    // Have we initialized global (root) handlers yet?
+    // This gets set to false in readConfiguration
+    private boolean initializedGlobalHandlers = true;
+    // True if JVM death is imminent and the exit hook has been called.
+    private boolean deathImminent;
+
+    static {
+        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+            @Override
+            public LogManager run() {
+                LogManager mgr = null;
+                String cname = null;
+                try {
+                    cname = System.getProperty("java.util.logging.manager");
+                    if (cname != null) {
+                        // Android-changed: Extract logic into the getClassInstance() helper.
+                        mgr = (LogManager) getClassInstance(cname).newInstance();
+                    }
+                } catch (Exception ex) {
+                    System.err.println("Could not load Logmanager \"" + cname + "\"");
+                    ex.printStackTrace();
+                }
+                if (mgr == null) {
+                    mgr = new LogManager();
+                }
+                return mgr;
+
+            }
+        });
+    }
+
+
+    // This private class is used as a shutdown hook.
+    // It does a "reset" to close all open handlers.
+    private class Cleaner extends Thread {
+
+        private Cleaner() {
+            /* Set context class loader to null in order to avoid
+             * keeping a strong reference to an application classloader.
+             */
+            this.setContextClassLoader(null);
+        }
+
+        @Override
+        public void run() {
+            // This is to ensure the LogManager.<clinit> is completed
+            // before synchronized block. Otherwise deadlocks are possible.
+            LogManager mgr = manager;
+
+            // If the global handlers haven't been initialized yet, we
+            // don't want to initialize them just so we can close them!
+            synchronized (LogManager.this) {
+                // Note that death is imminent.
+                deathImminent = true;
+                initializedGlobalHandlers = true;
+            }
+
+            // Do a reset to close all active handlers.
+            reset();
+        }
+    }
+
+
+    /**
+     * Protected constructor.  This is protected so that container applications
+     * (such as J2EE containers) can subclass the object.  It is non-public as
+     * it is intended that there only be one LogManager object, whose value is
+     * retrieved by calling LogManager.getLogManager.
+     */
+    protected LogManager() {
+        this(checkSubclassPermissions());
+    }
+
+    private LogManager(Void checked) {
+
+        // Add a shutdown hook to close the global handlers.
+        try {
+            Runtime.getRuntime().addShutdownHook(new Cleaner());
+        } catch (IllegalStateException e) {
+            // If the VM is already shutting down,
+            // We do not need to register shutdownHook.
+        }
+    }
+
+    private static Void checkSubclassPermissions() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // These permission will be checked in the LogManager constructor,
+            // in order to register the Cleaner() thread as a shutdown hook.
+            // Check them here to avoid the penalty of constructing the object
+            // etc...
+            sm.checkPermission(new RuntimePermission("shutdownHooks"));
+            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+        }
+        return null;
+    }
+
+    /**
+     * Lazy initialization: if this instance of manager is the global
+     * manager then this method will read the initial configuration and
+     * add the root logger and global logger by calling addLogger().
+     *
+     * Note that it is subtly different from what we do in LoggerContext.
+     * In LoggerContext we're patching up the logger context tree in order to add
+     * the root and global logger *to the context tree*.
+     *
+     * For this to work, addLogger() must have already have been called
+     * once on the LogManager instance for the default logger being
+     * added.
+     *
+     * This is why ensureLogManagerInitialized() needs to be called before
+     * any logger is added to any logger context.
+     *
+     */
+    private boolean initializedCalled = false;
+    private volatile boolean initializationDone = false;
+    final void ensureLogManagerInitialized() {
+        final LogManager owner = this;
+        if (initializationDone || owner != manager) {
+            // we don't want to do this twice, and we don't want to do
+            // this on private manager instances.
+            return;
+        }
+
+        // Maybe another thread has called ensureLogManagerInitialized()
+        // before us and is still executing it. If so we will block until
+        // the log manager has finished initialized, then acquire the monitor,
+        // notice that initializationDone is now true and return.
+        // Otherwise - we have come here first! We will acquire the monitor,
+        // see that initializationDone is still false, and perform the
+        // initialization.
+        //
+        synchronized(this) {
+            // If initializedCalled is true it means that we're already in
+            // the process of initializing the LogManager in this thread.
+            // There has been a recursive call to ensureLogManagerInitialized().
+            final boolean isRecursiveInitialization = (initializedCalled == true);
+
+            assert initializedCalled || !initializationDone
+                    : "Initialization can't be done if initialized has not been called!";
+
+            if (isRecursiveInitialization || initializationDone) {
+                // If isRecursiveInitialization is true it means that we're
+                // already in the process of initializing the LogManager in
+                // this thread. There has been a recursive call to
+                // ensureLogManagerInitialized(). We should not proceed as
+                // it would lead to infinite recursion.
+                //
+                // If initializationDone is true then it means the manager
+                // has finished initializing; just return: we're done.
+                return;
+            }
+            // Calling addLogger below will in turn call requiresDefaultLogger()
+            // which will call ensureLogManagerInitialized().
+            // We use initializedCalled to break the recursion.
+            initializedCalled = true;
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        assert rootLogger == null;
+                        assert initializedCalled && !initializationDone;
+
+                        // Read configuration.
+                        owner.readPrimordialConfiguration();
+
+                        // Create and retain Logger for the root of the namespace.
+                        owner.rootLogger = owner.new RootLogger();
+                        owner.addLogger(owner.rootLogger);
+                        if (!owner.rootLogger.isLevelInitialized()) {
+                            owner.rootLogger.setLevel(defaultLevel);
+                        }
+
+                        // Adding the global Logger.
+                        // Do not call Logger.getGlobal() here as this might trigger
+                        // subtle inter-dependency issues.
+                        @SuppressWarnings("deprecation")
+                        final Logger global = Logger.global;
+
+                        // Make sure the global logger will be registered in the
+                        // global manager
+                        owner.addLogger(global);
+                        return null;
+                    }
+                });
+            } finally {
+                initializationDone = true;
+            }
+        }
+    }
+
+    /**
+     * Returns the global LogManager object.
+     * @return the global LogManager object
+     */
+    public static LogManager getLogManager() {
+        if (manager != null) {
+            manager.ensureLogManagerInitialized();
+        }
+        return manager;
+    }
+
+    private void readPrimordialConfiguration() {
+        if (!readPrimordialConfiguration) {
+            synchronized (this) {
+                if (!readPrimordialConfiguration) {
+                    // If System.in/out/err are null, it's a good
+                    // indication that we're still in the
+                    // bootstrapping phase
+                    if (System.out == null) {
+                        return;
+                    }
+                    readPrimordialConfiguration = true;
+
+                    try {
+                        AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                                @Override
+                                public Void run() throws Exception {
+                                    readConfiguration();
+
+                                    // Platform loggers begin to delegate to java.util.logging.Logger
+                                    sun.util.logging.PlatformLogger.redirectPlatformLoggers();
+                                    return null;
+                                }
+                            });
+                    } catch (Exception ex) {
+                        assert false : "Exception raised while reading logging configuration: " + ex;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds an event listener to be invoked when the logging
+     * properties are re-read. Adding multiple instances of
+     * the same event Listener results in multiple entries
+     * in the property event listener table.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception NullPointerException if the PropertyChangeListener is null.
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        PropertyChangeListener listener = Objects.requireNonNull(l);
+        checkPermission();
+        synchronized (listenerMap) {
+            // increment the registration count if already registered
+            Integer value = listenerMap.get(listener);
+            value = (value == null) ? 1 : (value + 1);
+            listenerMap.put(listener, value);
+        }
+    }
+
+    /**
+     * Removes an event listener for property change events.
+     * If the same listener instance has been added to the listener table
+     * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
+     * then an equivalent number of
+     * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
+     * all instances of that listener from the listener table.
+     * <P>
+     * Returns silently if the given listener is not found.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener (can be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        checkPermission();
+        if (l != null) {
+            PropertyChangeListener listener = l;
+            synchronized (listenerMap) {
+                Integer value = listenerMap.get(listener);
+                if (value != null) {
+                    // remove from map if registration count is 1, otherwise
+                    // just decrement its count
+                    int i = value.intValue();
+                    if (i == 1) {
+                        listenerMap.remove(listener);
+                    } else {
+                        assert i > 1;
+                        listenerMap.put(listener, i - 1);
+                    }
+                }
+            }
+        }
+    }
+
+    // LoggerContext maps from AppContext
+    private WeakHashMap<Object, LoggerContext> contextsMap = null;
+
+    // Returns the LoggerContext for the user code (i.e. application or AppContext).
+    // Loggers are isolated from each AppContext.
+    private LoggerContext getUserContext() {
+        // Android-changed: Remove AWT specific hooks.
+        return userContext;
+    }
+
+    // The system context.
+    final LoggerContext getSystemContext() {
+        return systemContext;
+    }
+
+    private List<LoggerContext> contexts() {
+        List<LoggerContext> cxs = new ArrayList<>();
+        cxs.add(getSystemContext());
+        cxs.add(getUserContext());
+        return cxs;
+    }
+
+    // Find or create a specified logger instance. If a logger has
+    // already been created with the given name it is returned.
+    // Otherwise a new logger instance is created and registered
+    // in the LogManager global namespace.
+    // This method will always return a non-null Logger object.
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by addLogger().
+    //
+    // This method must delegate to the LogManager implementation to
+    // add a new Logger or return the one that has been added previously
+    // as a LogManager subclass may override the addLogger, getLogger,
+    // readConfiguration, and other methods.
+    Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        Logger result = getLogger(name);
+        if (result == null) {
+            // only allocate the new logger once
+            Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);
+            do {
+                if (addLogger(newLogger)) {
+                    // We successfully added the new Logger that we
+                    // created above so return it without refetching.
+                    return newLogger;
+                }
+
+                // We didn't add the new Logger that we created above
+                // because another thread added a Logger with the same
+                // name after our null check above and before our call
+                // to addLogger(). We have to refetch the Logger because
+                // addLogger() returns a boolean instead of the Logger
+                // reference itself. However, if the thread that created
+                // the other Logger is not holding a strong reference to
+                // the other Logger, then it is possible for the other
+                // Logger to be GC'ed after we saw it in addLogger() and
+                // before we can refetch it. If it has been GC'ed then
+                // we'll just loop around and try again.
+                result = getLogger(name);
+            } while (result == null);
+        }
+        return result;
+    }
+
+    Logger demandSystemLogger(String name, String resourceBundleName) {
+        // Add a system logger in the system context's namespace
+        final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
+
+        // Add the system logger to the LogManager's namespace if not exist
+        // so that there is only one single logger of the given name.
+        // System loggers are visible to applications unless a logger of
+        // the same name has been added.
+        Logger logger;
+        do {
+            // First attempt to call addLogger instead of getLogger
+            // This would avoid potential bug in custom LogManager.getLogger
+            // implementation that adds a logger if does not exist
+            if (addLogger(sysLogger)) {
+                // successfully added the new system logger
+                logger = sysLogger;
+            } else {
+                logger = getLogger(name);
+            }
+        } while (logger == null);
+
+        // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
+        if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) {
+            // if logger already exists but handlers not set
+            final Logger l = logger;
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    for (Handler hdl : l.accessCheckedHandlers()) {
+                        sysLogger.addHandler(hdl);
+                    }
+                    return null;
+                }
+            });
+        }
+        return sysLogger;
+    }
+
+    // Android-added: getClassInstance helper method, used in several places in this class.
+    private static Class getClassInstance(String cname) throws ClassNotFoundException {
+        try {
+            return ClassLoader.getSystemClassLoader().loadClass(cname);
+        } catch (ClassNotFoundException ex) {
+            return Thread.currentThread().getContextClassLoader().loadClass(cname);
+        }
+    }
+
+    // LoggerContext maintains the logger namespace per context.
+    // The default LogManager implementation has one system context and user
+    // context.  The system context is used to maintain the namespace for
+    // all system loggers and is queried by the system code.  If a system logger
+    // doesn't exist in the user context, it'll also be added to the user context.
+    // The user context is queried by the user code and all other loggers are
+    // added in the user context.
+    class LoggerContext {
+        // Table of named Loggers that maps names to Loggers.
+        private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
+        // Tree of named Loggers
+        private final LogNode root;
+        private LoggerContext() {
+            this.root = new LogNode(null, this);
+        }
+
+
+        // Tells whether default loggers are required in this context.
+        // If true, the default loggers will be lazily added.
+        final boolean requiresDefaultLoggers() {
+            final boolean requiresDefaultLoggers = (getOwner() == manager);
+            if (requiresDefaultLoggers) {
+                getOwner().ensureLogManagerInitialized();
+            }
+            return requiresDefaultLoggers;
+        }
+
+        // This context's LogManager.
+        final LogManager getOwner() {
+            return LogManager.this;
+        }
+
+        // This context owner's root logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getRootLogger() {
+            return getOwner().rootLogger;
+        }
+
+        // The global logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getGlobalLogger() {
+            // Android-changed: Fix SuppressWarnings from "deprecated" to "deprecation".
+            @SuppressWarnings("deprecation") // avoids initialization cycles.
+            final Logger global = Logger.global;
+            return global;
+        }
+
+        Logger demandLogger(String name, String resourceBundleName) {
+            // a LogManager subclass may have its own implementation to add and
+            // get a Logger.  So delegate to the LogManager to do the work.
+            final LogManager owner = getOwner();
+            return owner.demandLogger(name, resourceBundleName, null);
+        }
+
+
+        // Due to subtle deadlock issues getUserContext() no longer
+        // calls addLocalLogger(rootLogger);
+        // Therefore - we need to add the default loggers later on.
+        // Checks that the context is properly initialized
+        // This is necessary before calling e.g. find(name)
+        // or getLoggerNames()
+        //
+        private void ensureInitialized() {
+            if (requiresDefaultLoggers()) {
+                // Ensure that the root and global loggers are set.
+                ensureDefaultLogger(getRootLogger());
+                ensureDefaultLogger(getGlobalLogger());
+            }
+        }
+
+
+        synchronized Logger findLogger(String name) {
+            // ensure that this context is properly initialized before
+            // looking for loggers.
+            ensureInitialized();
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref == null) {
+                return null;
+            }
+            Logger logger = ref.get();
+            if (logger == null) {
+                // Hashtable holds stale weak reference
+                // to a logger which has been GC-ed.
+                ref.dispose();
+            }
+            return logger;
+        }
+
+        // This method is called before adding a logger to the
+        // context.
+        // 'logger' is the context that will be added.
+        // This method will ensure that the defaults loggers are added
+        // before adding 'logger'.
+        //
+        private void ensureAllDefaultLoggers(Logger logger) {
+            if (requiresDefaultLoggers()) {
+                final String name = logger.getName();
+                if (!name.isEmpty()) {
+                    ensureDefaultLogger(getRootLogger());
+                    if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+                        ensureDefaultLogger(getGlobalLogger());
+                    }
+                }
+            }
+        }
+
+        private void ensureDefaultLogger(Logger logger) {
+            // Used for lazy addition of root logger and global logger
+            // to a LoggerContext.
+
+            // This check is simple sanity: we do not want that this
+            // method be called for anything else than Logger.global
+            // or owner.rootLogger.
+            if (!requiresDefaultLoggers() || logger == null
+                    || logger != Logger.global && logger != LogManager.this.rootLogger) {
+
+                // the case where we have a non null logger which is neither
+                // Logger.global nor manager.rootLogger indicates a serious
+                // issue - as ensureDefaultLogger should never be called
+                // with any other loggers than one of these two (or null - if
+                // e.g manager.rootLogger is not yet initialized)...
+                assert logger == null;
+
+                return;
+            }
+
+            // Adds the logger if it's not already there.
+            if (!namedLoggers.containsKey(logger.getName())) {
+                // It is important to prevent addLocalLogger to
+                // call ensureAllDefaultLoggers when we're in the process
+                // off adding one of those default loggers - as this would
+                // immediately cause a stack overflow.
+                // Therefore we must pass addDefaultLoggersIfNeeded=false,
+                // even if requiresDefaultLoggers is true.
+                addLocalLogger(logger, false);
+            }
+        }
+
+        boolean addLocalLogger(Logger logger) {
+            // no need to add default loggers if it's not required
+            return addLocalLogger(logger, requiresDefaultLoggers());
+        }
+
+        // Add a logger to this context.  This method will only set its level
+        // and process parent loggers.  It doesn't set its handlers.
+        synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
+            // addDefaultLoggersIfNeeded serves to break recursion when adding
+            // default loggers. If we're adding one of the default loggers
+            // (we're being called from ensureDefaultLogger()) then
+            // addDefaultLoggersIfNeeded will be false: we don't want to
+            // call ensureAllDefaultLoggers again.
+            //
+            // Note: addDefaultLoggersIfNeeded can also be false when
+            //       requiresDefaultLoggers is false - since calling
+            //       ensureAllDefaultLoggers would have no effect in this case.
+            if (addDefaultLoggersIfNeeded) {
+                ensureAllDefaultLoggers(logger);
+            }
+
+            final String name = logger.getName();
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref != null) {
+                // Android-changed: Use refersTo().
+                if (ref.refersTo(null)) {
+                    // It's possible that the Logger was GC'ed after a
+                    // drainLoggerRefQueueBounded() call above so allow
+                    // a new one to be registered.
+                    ref.dispose();
+                } else {
+                    // We already have a registered logger with the given name.
+                    return false;
+                }
+            }
+
+            // We're adding a new logger.
+            // Note that we are creating a weak reference here.
+            final LogManager owner = getOwner();
+            logger.setLogManager(owner);
+            ref = owner.new LoggerWeakRef(logger);
+            namedLoggers.put(name, ref);
+
+            // Apply any initial level defined for the new logger, unless
+            // the logger's level is already initialized
+            Level level = owner.getLevelProperty(name + ".level", null);
+            if (level != null && !logger.isLevelInitialized()) {
+                doSetLevel(logger, level);
+            }
+
+            // instantiation of the handler is done in the LogManager.addLogger
+            // implementation as a handler class may be only visible to LogManager
+            // subclass for the custom log manager case
+            processParentHandlers(logger, name);
+
+            // Find the new node and its parent.
+            LogNode node = getNode(name);
+            node.loggerRef = ref;
+            Logger parent = null;
+            LogNode nodep = node.parent;
+            while (nodep != null) {
+                LoggerWeakRef nodeRef = nodep.loggerRef;
+                if (nodeRef != null) {
+                    parent = nodeRef.get();
+                    if (parent != null) {
+                        break;
+                    }
+                }
+                nodep = nodep.parent;
+            }
+
+            if (parent != null) {
+                doSetParent(logger, parent);
+            }
+            // Walk over the children and tell them we are their new parent.
+            node.walkAndSetParent(logger);
+            // new LogNode is ready so tell the LoggerWeakRef about it
+            ref.setNode(node);
+            return true;
+        }
+
+        synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
+            namedLoggers.remove(name, ref);
+        }
+
+        synchronized Enumeration<String> getLoggerNames() {
+            // ensure that this context is properly initialized before
+            // returning logger names.
+            ensureInitialized();
+            return namedLoggers.keys();
+        }
+
+        // If logger.getUseParentHandlers() returns 'true' and any of the logger's
+        // parents have levels or handlers defined, make sure they are instantiated.
+        private void processParentHandlers(final Logger logger, final String name) {
+            final LogManager owner = getOwner();
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    if (logger != owner.rootLogger) {
+                        boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
+                        if (!useParent) {
+                            logger.setUseParentHandlers(false);
+                        }
+                    }
+                    return null;
+                }
+            });
+
+            int ix = 1;
+            for (;;) {
+                int ix2 = name.indexOf(".", ix);
+                if (ix2 < 0) {
+                    break;
+                }
+                String pname = name.substring(0, ix2);
+                if (owner.getProperty(pname + ".level") != null ||
+                    owner.getProperty(pname + ".handlers") != null) {
+                    // This pname has a level/handlers definition.
+                    // Make sure it exists.
+                    demandLogger(pname, null);
+                }
+                ix = ix2+1;
+            }
+        }
+
+        // Gets a node in our tree of logger nodes.
+        // If necessary, create it.
+        LogNode getNode(String name) {
+            if (name == null || name.equals("")) {
+                return root;
+            }
+            LogNode node = root;
+            while (name.length() > 0) {
+                int ix = name.indexOf(".");
+                String head;
+                if (ix > 0) {
+                    head = name.substring(0, ix);
+                    name = name.substring(ix + 1);
+                } else {
+                    head = name;
+                    name = "";
+                }
+                if (node.children == null) {
+                    node.children = new HashMap<>();
+                }
+                LogNode child = node.children.get(head);
+                if (child == null) {
+                    child = new LogNode(node, this);
+                    node.children.put(head, child);
+                }
+                node = child;
+            }
+            return node;
+        }
+    }
+
+    final class SystemLoggerContext extends LoggerContext {
+        // Add a system logger in the system context's namespace as well as
+        // in the LogManager's namespace if not exist so that there is only
+        // one single logger of the given name.  System loggers are visible
+        // to applications unless a logger of the same name has been added.
+        @Override
+        Logger demandLogger(String name, String resourceBundleName) {
+            Logger result = findLogger(name);
+            if (result == null) {
+                // only allocate the new system logger once
+                Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true);
+                do {
+                    if (addLocalLogger(newLogger)) {
+                        // We successfully added the new Logger that we
+                        // created above so return it without refetching.
+                        result = newLogger;
+                    } else {
+                        // We didn't add the new Logger that we created above
+                        // because another thread added a Logger with the same
+                        // name after our null check above and before our call
+                        // to addLogger(). We have to refetch the Logger because
+                        // addLogger() returns a boolean instead of the Logger
+                        // reference itself. However, if the thread that created
+                        // the other Logger is not holding a strong reference to
+                        // the other Logger, then it is possible for the other
+                        // Logger to be GC'ed after we saw it in addLogger() and
+                        // before we can refetch it. If it has been GC'ed then
+                        // we'll just loop around and try again.
+                        result = findLogger(name);
+                    }
+                } while (result == null);
+            }
+            return result;
+        }
+    }
+
+    // Add new per logger handlers.
+    // We need to raise privilege here. All our decisions will
+    // be made based on the logging configuration, which can
+    // only be modified by trusted code.
+    private void loadLoggerHandlers(final Logger logger, final String name,
+                                    final String handlersPropertyName)
+    {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                String names[] = parseClassNames(handlersPropertyName);
+                for (int i = 0; i < names.length; i++) {
+                    String word = names[i];
+                    try {
+                        // Android-changed: Fall back from the system to the context classloader.
+                        // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                        Class<?> clz = getClassInstance(word);
+                        Handler hdl = (Handler) clz.newInstance();
+                        // Check if there is a property defining the
+                        // this handler's level.
+                        String levs = getProperty(word + ".level");
+                        if (levs != null) {
+                            Level l = Level.findLevel(levs);
+                            if (l != null) {
+                                hdl.setLevel(l);
+                            } else {
+                                // Probably a bad level. Drop through.
+                                System.err.println("Can't set level for " + word);
+                            }
+                        }
+                        // Add this Handler to the logger
+                        logger.addHandler(hdl);
+                    } catch (Exception ex) {
+                        System.err.println("Can't load log handler \"" + word + "\"");
+                        System.err.println("" + ex);
+                        ex.printStackTrace();
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
+
+    // loggerRefQueue holds LoggerWeakRef objects for Logger objects
+    // that have been GC'ed.
+    private final ReferenceQueue<Logger> loggerRefQueue
+        = new ReferenceQueue<>();
+
+    // Package-level inner class.
+    // Helper class for managing WeakReferences to Logger objects.
+    //
+    // LogManager.namedLoggers
+    //     - has weak references to all named Loggers
+    //     - namedLoggers keeps the LoggerWeakRef objects for the named
+    //       Loggers around until we can deal with the book keeping for
+    //       the named Logger that is being GC'ed.
+    // LogManager.LogNode.loggerRef
+    //     - has a weak reference to a named Logger
+    //     - the LogNode will also keep the LoggerWeakRef objects for
+    //       the named Loggers around; currently LogNodes never go away.
+    // Logger.kids
+    //     - has a weak reference to each direct child Logger; this
+    //       includes anonymous and named Loggers
+    //     - anonymous Loggers are always children of the rootLogger
+    //       which is a strong reference; rootLogger.kids keeps the
+    //       LoggerWeakRef objects for the anonymous Loggers around
+    //       until we can deal with the book keeping.
+    //
+    final class LoggerWeakRef extends WeakReference<Logger> {
+        private String                name;       // for namedLoggers cleanup
+        private LogNode               node;       // for loggerRef cleanup
+        private WeakReference<Logger> parentRef;  // for kids cleanup
+        private boolean disposed = false;         // avoid calling dispose twice
+
+        LoggerWeakRef(Logger logger) {
+            super(logger, loggerRefQueue);
+
+            name = logger.getName();  // save for namedLoggers cleanup
+        }
+
+        // dispose of this LoggerWeakRef object
+        void dispose() {
+            // Avoid calling dispose twice. When a Logger is gc'ed, its
+            // LoggerWeakRef will be enqueued.
+            // However, a new logger of the same name may be added (or looked
+            // up) before the queue is drained. When that happens, dispose()
+            // will be called by addLocalLogger() or findLogger().
+            // Later when the queue is drained, dispose() will be called again
+            // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
+            // avoids processing the data twice (even though the code should
+            // now be reentrant).
+            synchronized(this) {
+                // Note to maintainers:
+                // Be careful not to call any method that tries to acquire
+                // another lock from within this block - as this would surely
+                // lead to deadlocks, given that dispose() can be called by
+                // multiple threads, and from within different synchronized
+                // methods/blocks.
+                if (disposed) return;
+                disposed = true;
+            }
+
+            final LogNode n = node;
+            if (n != null) {
+                // n.loggerRef can only be safely modified from within
+                // a lock on LoggerContext. removeLoggerRef is already
+                // synchronized on LoggerContext so calling
+                // n.context.removeLoggerRef from within this lock is safe.
+                synchronized (n.context) {
+                    // if we have a LogNode, then we were a named Logger
+                    // so clear namedLoggers weak ref to us
+                    n.context.removeLoggerRef(name, this);
+                    name = null;  // clear our ref to the Logger's name
+
+                    // LogNode may have been reused - so only clear
+                    // LogNode.loggerRef if LogNode.loggerRef == this
+                    if (n.loggerRef == this) {
+                        n.loggerRef = null;  // clear LogNode's weak ref to us
+                    }
+                    node = null;            // clear our ref to LogNode
+                }
+            }
+
+            if (parentRef != null) {
+                // this LoggerWeakRef has or had a parent Logger
+                Logger parent = parentRef.get();
+                if (parent != null) {
+                    // the parent Logger is still there so clear the
+                    // parent Logger's weak ref to us
+                    parent.removeChildLogger(this);
+                }
+                parentRef = null;  // clear our weak ref to the parent Logger
+            }
+        }
+
+        // set the node field to the specified value
+        void setNode(LogNode node) {
+            this.node = node;
+        }
+
+        // set the parentRef field to the specified value
+        void setParentRef(WeakReference<Logger> parentRef) {
+            this.parentRef = parentRef;
+        }
+    }
+
+    // Package-level method.
+    // Drain some Logger objects that have been GC'ed.
+    //
+    // drainLoggerRefQueueBounded() is called by addLogger() below
+    // and by Logger.getAnonymousLogger(String) so we'll drain up to
+    // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
+    //
+    // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
+    // us about a 50/50 mix in increased weak ref counts versus
+    // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 anonymous Loggers:
+    //   - test duration 1 minute
+    //   - sample size of 125 sets of 400
+    //   - average: 1.99 ms
+    //   - minimum: 0.57 ms
+    //   - maximum: 25.3 ms
+    //
+    // The same config gives us a better decreased weak ref count
+    // than increased weak ref count in the LoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 named Loggers:
+    //   - test duration 2 minutes
+    //   - sample size of 506 sets of 400
+    //   - average: 0.57 ms
+    //   - minimum: 0.02 ms
+    //   - maximum: 10.9 ms
+    //
+    private final static int MAX_ITERATIONS = 400;
+    final void drainLoggerRefQueueBounded() {
+        for (int i = 0; i < MAX_ITERATIONS; i++) {
+            if (loggerRefQueue == null) {
+                // haven't finished loading LogManager yet
+                break;
+            }
+
+            LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
+            if (ref == null) {
+                break;
+            }
+            // a Logger object has been GC'ed so clean it up
+            ref.dispose();
+        }
+    }
+
+    /**
+     * Add a named logger.  This does nothing and returns false if a logger
+     * with the same name is already registered.
+     * <p>
+     * The Logger factory methods call this method to register each
+     * newly created Logger.
+     * <p>
+     * The application should retain its own reference to the Logger
+     * object to avoid it being garbage collected.  The LogManager
+     * may only retain a weak reference.
+     *
+     * @param   logger the new logger.
+     * @return  true if the argument logger was registered successfully,
+     *          false if a logger of that name already exists.
+     * @exception NullPointerException if the logger name is null.
+     */
+    public boolean addLogger(Logger logger) {
+        final String name = logger.getName();
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        drainLoggerRefQueueBounded();
+        LoggerContext cx = getUserContext();
+        if (cx.addLocalLogger(logger)) {
+            // Do we have a per logger handler too?
+            // Note: this will add a 200ms penalty
+            loadLoggerHandlers(logger, name, name + ".handlers");
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // Private method to set a level on a logger.
+    // If necessary, we raise privilege before doing the call.
+    private static void doSetLevel(final Logger logger, final Level level) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setLevel(level);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setLevel.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setLevel(level);
+                return null;
+            }});
+    }
+
+    // Private method to set a parent on a logger.
+    // If necessary, we raise privilege before doing the setParent call.
+    private static void doSetParent(final Logger logger, final Logger parent) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setParent(parent);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setParent.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setParent(parent);
+                return null;
+            }});
+    }
+
+    /**
+     * Method to find a named logger.
+     * <p>
+     * Note that since untrusted code may create loggers with
+     * arbitrary names this method should not be relied on to
+     * find Loggers for security sensitive logging.
+     * It is also important to note that the Logger associated with the
+     * String {@code name} may be garbage collected at any time if there
+     * is no strong reference to the Logger. The caller of this method
+     * must check the return value for null in order to properly handle
+     * the case where the Logger has been garbage collected.
+     * <p>
+     * @param name name of the logger
+     * @return  matching logger or null if none is found
+     */
+    public Logger getLogger(String name) {
+        return getUserContext().findLogger(name);
+    }
+
+    /**
+     * Get an enumeration of known logger names.
+     * <p>
+     * Note:  Loggers may be added dynamically as new classes are loaded.
+     * This method only reports on the loggers that are currently registered.
+     * It is also important to note that this method only returns the name
+     * of a Logger, not a strong reference to the Logger itself.
+     * The returned String does nothing to prevent the Logger from being
+     * garbage collected. In particular, if the returned name is passed
+     * to {@code LogManager.getLogger()}, then the caller must check the
+     * return value from {@code LogManager.getLogger()} for null to properly
+     * handle the case where the Logger has been garbage collected in the
+     * time since its name was returned by this method.
+     * <p>
+     * @return  enumeration of logger name strings
+     */
+    public Enumeration<String> getLoggerNames() {
+        return getUserContext().getLoggerNames();
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration.
+     * <p>
+     * The same rules are used for locating the configuration properties
+     * as are used at startup.  So normally the logging properties will
+     * be re-read from the same file that was used at startup.
+     * <P>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     * <p>
+     * A PropertyChangeEvent will be fired after the properties are read.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are IO problems reading the configuration.
+     */
+    public void readConfiguration() throws IOException, SecurityException {
+        checkPermission();
+
+        // if a configuration class is specified, load it and use it.
+        String cname = System.getProperty("java.util.logging.config.class");
+        if (cname != null) {
+            try {
+                // Instantiate the named class.  It is its constructor's
+                // responsibility to initialize the logging configuration, by
+                // calling readConfiguration(InputStream) with a suitable stream.
+                // Android-changed: Extract logic into the getClassInstance() helper.
+                getClassInstance(cname).newInstance();
+                return;
+            } catch (Exception ex) {
+                System.err.println("Logging configuration class \"" + cname + "\" failed");
+                System.err.println("" + ex);
+                // keep going and useful config file.
+            }
+        }
+
+        String fname = System.getProperty("java.util.logging.config.file");
+        if (fname == null) {
+            fname = System.getProperty("java.home");
+            if (fname == null) {
+                throw new Error("Can't find java.home ??");
+            }
+            File f = new File(fname, "lib");
+            f = new File(f, "logging.properties");
+            fname = f.getCanonicalPath();
+        }
+
+        // BEGIN Android-changed: Look in the boot class-path jar files for the logging.properties.
+        // It may not be present in the file system.
+        /*
+        try (final InputStream in = new FileInputStream(fname)) {
+            final BufferedInputStream bin = new BufferedInputStream(in);
+            readConfiguration(bin);
+        }
+        */
+        InputStream in;
+        try {
+            in = new FileInputStream(fname);
+        } catch (Exception e) {
+            in = LogManager.class.getResourceAsStream("logging.properties");
+            if (in == null) {
+                throw e;
+            }
+        }
+
+        BufferedInputStream bin = new BufferedInputStream(in);
+        try {
+            readConfiguration(bin);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+        // END Android-changed: Look in the boot class-path jar files for the logging.properties.
+    }
+
+    /**
+     * Reset the logging configuration.
+     * <p>
+     * For all named loggers, the reset operation removes and closes
+     * all Handlers and (except for the root logger) sets the level
+     * to null.  The root logger's level is set to Level.INFO.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+
+    public void reset() throws SecurityException {
+        checkPermission();
+        synchronized (this) {
+            props = new Properties();
+            // Since we are doing a reset we no longer want to initialize
+            // the global handlers, if they haven't been initialized yet.
+            initializedGlobalHandlers = true;
+        }
+        for (LoggerContext cx : contexts()) {
+            Enumeration<String> enum_ = cx.getLoggerNames();
+            while (enum_.hasMoreElements()) {
+                String name = enum_.nextElement();
+                Logger logger = cx.findLogger(name);
+                if (logger != null) {
+                    resetLogger(logger);
+                }
+            }
+        }
+    }
+
+    // Private method to reset an individual target logger.
+    private void resetLogger(Logger logger) {
+        // Close all the Logger's handlers.
+        Handler[] targets = logger.getHandlers();
+        for (int i = 0; i < targets.length; i++) {
+            Handler h = targets[i];
+            logger.removeHandler(h);
+            try {
+                h.close();
+            } catch (Exception ex) {
+                // Problems closing a handler?  Keep going...
+            }
+        }
+        String name = logger.getName();
+        if (name != null && name.equals("")) {
+            // This is the root logger.
+            logger.setLevel(defaultLevel);
+        } else {
+            logger.setLevel(null);
+        }
+    }
+
+    // get a list of whitespace separated classnames from a property.
+    private String[] parseClassNames(String propertyName) {
+        String hands = getProperty(propertyName);
+        if (hands == null) {
+            return new String[0];
+        }
+        hands = hands.trim();
+        int ix = 0;
+        final List<String> result = new ArrayList<>();
+        while (ix < hands.length()) {
+            int end = ix;
+            while (end < hands.length()) {
+                if (Character.isWhitespace(hands.charAt(end))) {
+                    break;
+                }
+                if (hands.charAt(end) == ',') {
+                    break;
+                }
+                end++;
+            }
+            String word = hands.substring(ix, end);
+            ix = end+1;
+            word = word.trim();
+            if (word.length() == 0) {
+                continue;
+            }
+            result.add(word);
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration
+     * from the given stream, which should be in java.util.Properties format.
+     * A PropertyChangeEvent will be fired after the properties are read.
+     * <p>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     *
+     * @param ins       stream to read properties from
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are problems reading from the stream.
+     */
+    public void readConfiguration(InputStream ins) throws IOException, SecurityException {
+        checkPermission();
+        reset();
+
+        // Load the properties
+        props.load(ins);
+        // Instantiate new configuration objects.
+        String names[] = parseClassNames("config");
+
+        for (int i = 0; i < names.length; i++) {
+            String word = names[i];
+            try {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                // clz.newInstance();
+                getClassInstance(word).newInstance();
+            } catch (Exception ex) {
+                System.err.println("Can't load config class \"" + word + "\"");
+                System.err.println("" + ex);
+                // ex.printStackTrace();
+            }
+        }
+
+        // Set levels on any pre-existing loggers, based on the new properties.
+        setLevelsOnExistingLoggers();
+
+        // Notify any interested parties that our properties have changed.
+        // We first take a copy of the listener map so that we aren't holding any
+        // locks when calling the listeners.
+        Map<Object,Integer> listeners = null;
+        synchronized (listenerMap) {
+            if (!listenerMap.isEmpty())
+                listeners = new HashMap<>(listenerMap);
+        }
+        if (listeners != null) {
+            assert Beans.isBeansPresent();
+            Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null);
+            for (Map.Entry<Object,Integer> entry : listeners.entrySet()) {
+                Object listener = entry.getKey();
+                int count = entry.getValue().intValue();
+                for (int i = 0; i < count; i++) {
+                    Beans.invokePropertyChange(listener, ev);
+                }
+            }
+        }
+
+
+        // Note that we need to reinitialize global handles when
+        // they are first referenced.
+        synchronized (this) {
+            initializedGlobalHandlers = false;
+        }
+    }
+
+    /**
+     * Get the value of a logging property.
+     * The method returns null if the property is not found.
+     * @param name      property name
+     * @return          property value
+     */
+    public String getProperty(String name) {
+        return props.getProperty(name);
+    }
+
+    // Package private method to get a String property.
+    // If the property is not defined we return the given
+    // default value.
+    String getStringProperty(String name, String defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.trim();
+    }
+
+    // Package private method to get an integer property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    int getIntProperty(String name, int defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(val.trim());
+        } catch (Exception ex) {
+            return defaultValue;
+        }
+    }
+
+    // Package private method to get a boolean property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    boolean getBooleanProperty(String name, boolean defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        val = val.toLowerCase();
+        if (val.equals("true") || val.equals("1")) {
+            return true;
+        } else if (val.equals("false") || val.equals("0")) {
+            return false;
+        }
+        return defaultValue;
+    }
+
+    // Package private method to get a Level property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    Level getLevelProperty(String name, Level defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        Level l = Level.findLevel(val.trim());
+        return l != null ? l : defaultValue;
+    }
+
+    // Package private method to get a filter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Filter getFilterProperty(String name, Filter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Filter) clz.newInstance();
+                return (Filter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+
+    // Package private method to get a formatter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Formatter getFormatterProperty(String name, Formatter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Formatter) clz.newInstance();
+                return (Formatter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+    // Private method to load the global handlers.
+    // We do the real work lazily, when the global handlers
+    // are first used.
+    private synchronized void initializeGlobalHandlers() {
+        if (initializedGlobalHandlers) {
+            return;
+        }
+
+        initializedGlobalHandlers = true;
+
+        if (deathImminent) {
+            // Aaargh...
+            // The VM is shutting down and our exit hook has been called.
+            // Avoid allocating global handlers.
+            return;
+        }
+        loadLoggerHandlers(rootLogger, null, "handlers");
+    }
+
+    private final Permission controlPermission = new LoggingPermission("control", null);
+
+    void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(controlPermission);
+    }
+
+    /**
+     * Check that the current context is trusted to modify the logging
+     * configuration.  This requires LoggingPermission("control").
+     * <p>
+     * If the check fails we throw a SecurityException, otherwise
+     * we return normally.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    public void checkAccess() throws SecurityException {
+        checkPermission();
+    }
+
+    // Nested class to represent a node in our tree of named loggers.
+    private static class LogNode {
+        HashMap<String,LogNode> children;
+        LoggerWeakRef loggerRef;
+        LogNode parent;
+        final LoggerContext context;
+
+        LogNode(LogNode parent, LoggerContext context) {
+            this.parent = parent;
+            this.context = context;
+        }
+
+        // Recursive method to walk the tree below a node and set
+        // a new parent logger.
+        void walkAndSetParent(Logger parent) {
+            if (children == null) {
+                return;
+            }
+            Iterator<LogNode> values = children.values().iterator();
+            while (values.hasNext()) {
+                LogNode node = values.next();
+                LoggerWeakRef ref = node.loggerRef;
+                Logger logger = (ref == null) ? null : ref.get();
+                if (logger == null) {
+                    node.walkAndSetParent(parent);
+                } else {
+                    doSetParent(logger, parent);
+                }
+            }
+        }
+    }
+
+    // We use a subclass of Logger for the root logger, so
+    // that we only instantiate the global handlers when they
+    // are first needed.
+    private final class RootLogger extends Logger {
+        private RootLogger() {
+            // We do not call the protected Logger two args constructor here,
+            // to avoid calling LogManager.getLogManager() from within the
+            // RootLogger constructor.
+            super("", null, null, LogManager.this, true);
+        }
+
+        @Override
+        public void log(LogRecord record) {
+            // Make sure that the global handlers have been instantiated.
+            initializeGlobalHandlers();
+            super.log(record);
+        }
+
+        @Override
+        public void addHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.addHandler(h);
+        }
+
+        @Override
+        public void removeHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.removeHandler(h);
+        }
+
+        @Override
+        Handler[] accessCheckedHandlers() {
+            initializeGlobalHandlers();
+            return super.accessCheckedHandlers();
+        }
+    }
+
+
+    // Private method to be called when the configuration has
+    // changed to apply any level settings to any pre-existing loggers.
+    synchronized private void setLevelsOnExistingLoggers() {
+        Enumeration<?> enum_ = props.propertyNames();
+        while (enum_.hasMoreElements()) {
+            String key = (String)enum_.nextElement();
+            if (!key.endsWith(".level")) {
+                // Not a level definition.
+                continue;
+            }
+            int ix = key.length() - 6;
+            String name = key.substring(0, ix);
+            Level level = getLevelProperty(key, null);
+            if (level == null) {
+                System.err.println("Bad level value for property: " + key);
+                continue;
+            }
+            for (LoggerContext cx : contexts()) {
+                Logger l = cx.findLogger(name);
+                if (l == null) {
+                    continue;
+                }
+                l.setLevel(level);
+            }
+        }
+    }
+
+    // Management Support
+    private static LoggingMXBean loggingMXBean = null;
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * String representation of the {@code ObjectName} for the management interface
+     * for the logging facility.
+     *
+     * @see java.util.logging.LoggingMXBean
+     *
+     * @since 1.5
+     */
+    public final static String LOGGING_MXBEAN_NAME
+        = "java.util.logging:type=Logging";
+
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * Returns <tt>LoggingMXBean</tt> for managing loggers.
+     *
+     * @return a {@link LoggingMXBean} object.
+     *
+     * @since 1.5
+     */
+    public static synchronized LoggingMXBean getLoggingMXBean() {
+        if (loggingMXBean == null) {
+            loggingMXBean =  new Logging();
+        }
+        return loggingMXBean;
+    }
+
+    /**
+     * A class that provides access to the java.beans.PropertyChangeListener
+     * and java.beans.PropertyChangeEvent without creating a static dependency
+     * on java.beans. This class can be removed once the addPropertyChangeListener
+     * and removePropertyChangeListener methods are removed.
+     */
+    private static class Beans {
+        private static final Class<?> propertyChangeListenerClass =
+            getClass("java.beans.PropertyChangeListener");
+
+        private static final Class<?> propertyChangeEventClass =
+            getClass("java.beans.PropertyChangeEvent");
+
+        private static final Method propertyChangeMethod =
+            getMethod(propertyChangeListenerClass,
+                      "propertyChange",
+                      propertyChangeEventClass);
+
+        private static final Constructor<?> propertyEventCtor =
+            getConstructor(propertyChangeEventClass,
+                           Object.class,
+                           String.class,
+                           Object.class,
+                           Object.class);
+
+        private static Class<?> getClass(String name) {
+            try {
+                return Class.forName(name, true, Beans.class.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                return null;
+            }
+        }
+        private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getDeclaredConstructor(types);
+            } catch (NoSuchMethodException x) {
+                throw new AssertionError(x);
+            }
+        }
+
+        private static Method getMethod(Class<?> c, String name, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getMethod(name, types);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        /**
+         * Returns {@code true} if java.beans is present.
+         */
+        static boolean isBeansPresent() {
+            return propertyChangeListenerClass != null &&
+                   propertyChangeEventClass != null;
+        }
+
+        /**
+         * Returns a new PropertyChangeEvent with the given source, property
+         * name, old and new values.
+         */
+        static Object newPropertyChangeEvent(Object source, String prop,
+                                             Object oldValue, Object newValue)
+        {
+            try {
+                return propertyEventCtor.newInstance(source, prop, oldValue, newValue);
+            } catch (InstantiationException | IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+
+        /**
+         * Invokes the given PropertyChangeListener's propertyChange method
+         * with the given event.
+         */
+        static void invokePropertyChange(Object listener, Object ev) {
+            try {
+                propertyChangeMethod.invoke(listener, ev);
+            } catch (IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/logging/LogRecord.java b/android-35/java/util/logging/LogRecord.java
new file mode 100644
index 0000000..3b0e518
--- /dev/null
+++ b/android-35/java/util/logging/LogRecord.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import dalvik.system.VMStack;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.io.*;
+
+/**
+ * LogRecord objects are used to pass logging requests between
+ * the logging framework and individual log Handlers.
+ * <p>
+ * When a LogRecord is passed into the logging framework it
+ * logically belongs to the framework and should no longer be
+ * used or updated by the client application.
+ * <p>
+ * Note that if the client application has not specified an
+ * explicit source method name and source class name, then the
+ * LogRecord class will infer them automatically when they are
+ * first accessed (due to a call on getSourceMethodName or
+ * getSourceClassName) by analyzing the call stack.  Therefore,
+ * if a logging Handler wants to pass off a LogRecord to another
+ * thread, or to transmit it over RMI, and if it wishes to subsequently
+ * obtain method name or class name information it should call
+ * one of getSourceClassName or getSourceMethodName to force
+ * the values to be filled in.
+ * <p>
+ * <b> Serialization notes:</b>
+ * <ul>
+ * <li>The LogRecord class is serializable.
+ *
+ * <li> Because objects in the parameters array may not be serializable,
+ * during serialization all objects in the parameters array are
+ * written as the corresponding Strings (using Object.toString).
+ *
+ * <li> The ResourceBundle is not transmitted as part of the serialized
+ * form, but the resource bundle name is, and the recipient object's
+ * readObject method will attempt to locate a suitable resource bundle.
+ *
+ * </ul>
+ *
+ * @since 1.4
+ */
+
+public class LogRecord implements java.io.Serializable {
+    private static final AtomicLong globalSequenceNumber
+        = new AtomicLong(0);
+
+    /**
+     * The default value of threadID will be the current thread's
+     * thread id, for ease of correlation, unless it is greater than
+     * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
+     * our promise to keep threadIDs unique by avoiding collisions due
+     * to 32-bit wraparound.  Unfortunately, LogRecord.getThreadID()
+     * returns int, while Thread.getId() returns long.
+     */
+    private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
+
+    private static final AtomicInteger nextThreadId
+        = new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
+
+    private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
+
+    /**
+     * @serial Logging message level
+     */
+    private Level level;
+
+    /**
+     * @serial Sequence number
+     */
+    private long sequenceNumber;
+
+    /**
+     * @serial Class that issued logging call
+     */
+    private String sourceClassName;
+
+    /**
+     * @serial Method that issued logging call
+     */
+    private String sourceMethodName;
+
+    /**
+     * @serial Non-localized raw message text
+     */
+    private String message;
+
+    /**
+     * @serial Thread ID for thread that issued logging call.
+     */
+    private int threadID;
+
+    /**
+     * @serial Event time in milliseconds since 1970
+     */
+    private long millis;
+
+    /**
+     * @serial The Throwable (if any) associated with log message
+     */
+    private Throwable thrown;
+
+    /**
+     * @serial Name of the source Logger.
+     */
+    private String loggerName;
+
+    /**
+     * @serial Resource bundle name to localized log message.
+     */
+    private String resourceBundleName;
+
+    private transient boolean needToInferCaller;
+    private transient Object parameters[];
+    private transient ResourceBundle resourceBundle;
+
+    /**
+     * Returns the default value for a new LogRecord's threadID.
+     */
+    private int defaultThreadID() {
+        long tid = Thread.currentThread().getId();
+        if (tid < MIN_SEQUENTIAL_THREAD_ID) {
+            return (int) tid;
+        } else {
+            Integer id = threadIds.get();
+            if (id == null) {
+                id = nextThreadId.getAndIncrement();
+                threadIds.set(id);
+            }
+            return id;
+        }
+    }
+
+    /**
+     * Construct a LogRecord with the given level and message values.
+     * <p>
+     * The sequence property will be initialized with a new unique value.
+     * These sequence values are allocated in increasing order within a VM.
+     * <p>
+     * The millis property will be initialized to the current time.
+     * <p>
+     * The thread ID property will be initialized with a unique ID for
+     * the current thread.
+     * <p>
+     * All other properties will be initialized to "null".
+     *
+     * @param level  a logging level value
+     * @param msg  the raw non-localized logging message (may be null)
+     */
+    public LogRecord(Level level, String msg) {
+        // Make sure level isn't null, by calling random method.
+        level.getClass();
+        this.level = level;
+        message = msg;
+        // Assign a thread ID and a unique sequence number.
+        sequenceNumber = globalSequenceNumber.getAndIncrement();
+        threadID = defaultThreadID();
+        millis = System.currentTimeMillis();
+        needToInferCaller = true;
+   }
+
+    /**
+     * Get the source Logger's name.
+     *
+     * @return source logger name (may be null)
+     */
+    public String getLoggerName() {
+        return loggerName;
+    }
+
+    /**
+     * Set the source Logger's name.
+     *
+     * @param name   the source logger name (may be null)
+     */
+    public void setLoggerName(String name) {
+        loggerName = name;
+    }
+
+    /**
+     * Get the localization resource bundle
+     * <p>
+     * This is the ResourceBundle that should be used to localize
+     * the message string before formatting it.  The result may
+     * be null if the message is not localizable, or if no suitable
+     * ResourceBundle is available.
+     * @return the localization resource bundle
+     */
+    public ResourceBundle getResourceBundle() {
+        return resourceBundle;
+    }
+
+    /**
+     * Set the localization resource bundle.
+     *
+     * @param bundle  localization bundle (may be null)
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        resourceBundle = bundle;
+    }
+
+    /**
+     * Get the localization resource bundle name
+     * <p>
+     * This is the name for the ResourceBundle that should be
+     * used to localize the message string before formatting it.
+     * The result may be null if the message is not localizable.
+     * @return the localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Set the localization resource bundle name.
+     *
+     * @param name  localization bundle name (may be null)
+     */
+    public void setResourceBundleName(String name) {
+        resourceBundleName = name;
+    }
+
+    /**
+     * Get the logging message level, for example Level.SEVERE.
+     * @return the logging message level
+     */
+    public Level getLevel() {
+        return level;
+    }
+
+    /**
+     * Set the logging message level, for example Level.SEVERE.
+     * @param level the logging message level
+     */
+    public void setLevel(Level level) {
+        if (level == null) {
+            throw new NullPointerException();
+        }
+        this.level = level;
+    }
+
+    /**
+     * Get the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord
+     * constructor, which assigns unique sequence numbers to
+     * each new LogRecord in increasing order.
+     * @return the sequence number
+     */
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
+     * Set the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord constructor,
+     * so it should not normally be necessary to use this method.
+     * @param seq the sequence number
+     */
+    public void setSequenceNumber(long seq) {
+        sequenceNumber = seq;
+    }
+
+    /**
+     * Get the  name of the class that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceClassName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source class name
+     */
+    public String getSourceClassName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceClassName;
+    }
+
+    /**
+     * Set the name of the class that (allegedly) issued the logging request.
+     *
+     * @param sourceClassName the source class name (may be null)
+     */
+    public void setSourceClassName(String sourceClassName) {
+        this.sourceClassName = sourceClassName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the  name of the method that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceMethodName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source method name
+     */
+    public String getSourceMethodName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceMethodName;
+    }
+
+    /**
+     * Set the name of the method that (allegedly) issued the logging request.
+     *
+     * @param sourceMethodName the source method name (may be null)
+     */
+    public void setSourceMethodName(String sourceMethodName) {
+        this.sourceMethodName = sourceMethodName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the "raw" log message, before localization or formatting.
+     * <p>
+     * May be null, which is equivalent to the empty string "".
+     * <p>
+     * This message may be either the final text or a localization key.
+     * <p>
+     * During formatting, if the source logger has a localization
+     * ResourceBundle and if that ResourceBundle has an entry for
+     * this message string, then the message string is replaced
+     * with the localized value.
+     *
+     * @return the raw message string
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Set the "raw" log message, before localization or formatting.
+     *
+     * @param message the raw message string (may be null)
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    /**
+     * Get the parameters to the log message.
+     *
+     * @return the log message parameters.  May be null if
+     *                  there are no parameters.
+     */
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Set the parameters to the log message.
+     *
+     * @param parameters the log message parameters. (may be null)
+     */
+    public void setParameters(Object parameters[]) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Get an identifier for the thread where the message originated.
+     * <p>
+     * This is a thread identifier within the Java VM and may or
+     * may not map to any operating system ID.
+     *
+     * @return thread ID
+     */
+    public int getThreadID() {
+        return threadID;
+    }
+
+    /**
+     * Set an identifier for the thread where the message originated.
+     * @param threadID  the thread ID
+     */
+    public void setThreadID(int threadID) {
+        this.threadID = threadID;
+    }
+
+    /**
+     * Get event time in milliseconds since 1970.
+     *
+     * @return event time in millis since 1970
+     */
+    public long getMillis() {
+        return millis;
+    }
+
+    /**
+     * Set event time.
+     *
+     * @param millis event time in millis since 1970
+     */
+    public void setMillis(long millis) {
+        this.millis = millis;
+    }
+
+    /**
+     * Get any throwable associated with the log record.
+     * <p>
+     * If the event involved an exception, this will be the
+     * exception object. Otherwise null.
+     *
+     * @return a throwable
+     */
+    public Throwable getThrown() {
+        return thrown;
+    }
+
+    /**
+     * Set a throwable associated with the log event.
+     *
+     * @param thrown  a throwable (may be null)
+     */
+    public void setThrown(Throwable thrown) {
+        this.thrown = thrown;
+    }
+
+    private static final long serialVersionUID = 5372048053134512534L;
+
+    /**
+     * @serialData Default fields, followed by a two byte version number
+     * (major byte, followed by minor byte), followed by information on
+     * the log record parameter array.  If there is no parameter array,
+     * then -1 is written.  If there is a parameter array (possible of zero
+     * length) then the array length is written as an integer, followed
+     * by String values for each parameter.  If a parameter is null, then
+     * a null String is written.  Otherwise the output of Object.toString()
+     * is written.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        // We have to call defaultWriteObject first.
+        out.defaultWriteObject();
+
+        // Write our version number.
+        out.writeByte(1);
+        out.writeByte(0);
+        if (parameters == null) {
+            out.writeInt(-1);
+            return;
+        }
+        out.writeInt(parameters.length);
+        // Write string values for the parameters.
+        for (int i = 0; i < parameters.length; i++) {
+            if (parameters[i] == null) {
+                out.writeObject(null);
+            } else {
+                out.writeObject(parameters[i].toString());
+            }
+        }
+    }
+
+    private void readObject(ObjectInputStream in)
+                        throws IOException, ClassNotFoundException {
+        // We have to call defaultReadObject first.
+        in.defaultReadObject();
+
+        // Read version number.
+        byte major = in.readByte();
+        byte minor = in.readByte();
+        if (major != 1) {
+            throw new IOException("LogRecord: bad version: " + major + "." + minor);
+        }
+        int len = in.readInt();
+        if (len < -1) {
+            throw new NegativeArraySizeException();
+        } else if (len == -1) {
+            parameters = null;
+        } else if (len < 255) {
+            parameters = new Object[len];
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = in.readObject();
+            }
+        } else {
+            List<Object> params = new ArrayList<>(Math.min(len, 1024));
+            for (int i = 0; i < len; i++) {
+                params.add(in.readObject());
+            }
+            parameters = params.toArray(new Object[params.size()]);
+        }
+        // If necessary, try to regenerate the resource bundle.
+        if (resourceBundleName != null) {
+            try {
+                // use system class loader to ensure the ResourceBundle
+                // instance is a different instance than null loader uses
+                final ResourceBundle bundle =
+                        ResourceBundle.getBundle(resourceBundleName,
+                                Locale.getDefault(),
+                                ClassLoader.getSystemClassLoader());
+                resourceBundle = bundle;
+            } catch (MissingResourceException ex) {
+                // Android-changed: Fall back to context classloader before giving up.
+                /*
+                // This is not a good place to throw an exception,
+                // so we simply leave the resourceBundle null.
+                resourceBundle = null;
+                */
+                try {
+                    resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(),
+                            Thread.currentThread().getContextClassLoader());
+                } catch (MissingResourceException innerE){
+                    // This is not a good place to throw an exception,
+                    // so we simply leave the resourceBundle null.
+                    resourceBundle = null;
+                }
+            }
+        }
+
+        needToInferCaller = false;
+    }
+
+    // Private method to infer the caller's class and method names
+    private void inferCaller() {
+        needToInferCaller = false;
+        // BEGIN Android-changed: Use VMStack.getThreadStackTrace.
+        /*
+        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
+        Throwable throwable = new Throwable();
+        int depth = access.getStackTraceDepth(throwable);
+        */
+        StackTraceElement[] stack = VMStack.getThreadStackTrace(Thread.currentThread());
+        int depth = stack.length;
+        // END Android-changed: Use VMStack.getThreadStackTrace.
+
+        boolean lookingForLogger = true;
+        for (int ix = 0; ix < depth; ix++) {
+            // Calling getStackTraceElement directly prevents the VM
+            // from paying the cost of building the entire stack frame.
+            //
+            // Android-changed: Use value from previous getThreadStackTrace call.
+            // StackTraceElement frame =
+            //     access.getStackTraceElement(throwable, ix);
+            StackTraceElement frame = stack[ix];
+            String cname = frame.getClassName();
+            boolean isLoggerImpl = isLoggerImplFrame(cname);
+            if (lookingForLogger) {
+                // Skip all frames until we have found the first logger frame.
+                if (isLoggerImpl) {
+                    lookingForLogger = false;
+                }
+            } else {
+                if (!isLoggerImpl) {
+                    // skip reflection call
+                    if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
+                       // We've found the relevant frame.
+                       setSourceClassName(cname);
+                       setSourceMethodName(frame.getMethodName());
+                       return;
+                    }
+                }
+            }
+        }
+        // We haven't found a suitable frame, so just punt.  This is
+        // OK as we are only committed to making a "best effort" here.
+    }
+
+    private boolean isLoggerImplFrame(String cname) {
+        // the log record could be created for a platform logger
+        return (cname.equals("java.util.logging.Logger") ||
+                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
+                cname.startsWith("sun.util.logging."));
+    }
+}
diff --git a/android-35/java/util/logging/Logger.java b/android-35/java/util/logging/Logger.java
new file mode 100644
index 0000000..61bbe4e
--- /dev/null
+++ b/android-35/java/util/logging/Logger.java
@@ -0,0 +1,2188 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A Logger object is used to log messages for a specific
+ * system or application component.  Loggers are normally named,
+ * using a hierarchical dot-separated namespace.  Logger names
+ * can be arbitrary strings, but they should normally be based on
+ * the package name or class name of the logged component, such
+ * as java.net or javax.swing.  In addition it is possible to create
+ * "anonymous" Loggers that are not stored in the Logger namespace.
+ * <p>
+ * Logger objects may be obtained by calls on one of the getLogger
+ * factory methods.  These will either create a new Logger or
+ * return a suitable existing Logger. It is important to note that
+ * the Logger returned by one of the {@code getLogger} factory methods
+ * may be garbage collected at any time if a strong reference to the
+ * Logger is not kept.
+ * <p>
+ * Logging messages will be forwarded to registered Handler
+ * objects, which can forward the messages to a variety of
+ * destinations, including consoles, files, OS logs, etc.
+ * <p>
+ * Each Logger keeps track of a "parent" Logger, which is its
+ * nearest existing ancestor in the Logger namespace.
+ * <p>
+ * Each Logger has a "Level" associated with it.  This reflects
+ * a minimum Level that this logger cares about.  If a Logger's
+ * level is set to <tt>null</tt>, then its effective level is inherited
+ * from its parent, which may in turn obtain it recursively from its
+ * parent, and so on up the tree.
+ * <p>
+ * The log level can be configured based on the properties from the
+ * logging configuration file, as described in the description
+ * of the LogManager class.  However it may also be dynamically changed
+ * by calls on the Logger.setLevel method.  If a logger's level is
+ * changed the change may also affect child loggers, since any child
+ * logger that has <tt>null</tt> as its level will inherit its
+ * effective level from its parent.
+ * <p>
+ * On each logging call the Logger initially performs a cheap
+ * check of the request level (e.g., SEVERE or FINE) against the
+ * effective log level of the logger.  If the request level is
+ * lower than the log level, the logging call returns immediately.
+ * <p>
+ * After passing this initial (cheap) test, the Logger will allocate
+ * a LogRecord to describe the logging message.  It will then call a
+ * Filter (if present) to do a more detailed check on whether the
+ * record should be published.  If that passes it will then publish
+ * the LogRecord to its output Handlers.  By default, loggers also
+ * publish to their parent's Handlers, recursively up the tree.
+ * <p>
+ * Each Logger may have a {@code ResourceBundle} associated with it.
+ * The {@code ResourceBundle} may be specified by name, using the
+ * {@link #getLogger(java.lang.String, java.lang.String)} factory
+ * method, or by value - using the {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+ * This bundle will be used for localizing logging messages.
+ * If a Logger does not have its own {@code ResourceBundle} or resource bundle
+ * name, then it will inherit the {@code ResourceBundle} or resource bundle name
+ * from its parent, recursively up the tree.
+ * <p>
+ * Most of the logger output methods take a "msg" argument.  This
+ * msg argument may be either a raw value or a localization key.
+ * During formatting, if the logger has (or inherits) a localization
+ * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
+ * the msg string, then the msg string is replaced by the localized value.
+ * Otherwise the original msg string is used.  Typically, formatters use
+ * java.text.MessageFormat style formatting to format parameters, so
+ * for example a format string "{0} {1}" would format two parameters
+ * as strings.
+ * <p>
+ * A set of methods alternatively take a "msgSupplier" instead of a "msg"
+ * argument.  These methods take a {@link Supplier}{@code <String>} function
+ * which is invoked to construct the desired log message only when the message
+ * actually is to be logged based on the effective log level thus eliminating
+ * unnecessary message construction. For example, if the developer wants to
+ * log system health status for diagnosis, with the String-accepting version,
+ * the code would look like:
+ <pre><code>
+
+   class DiagnosisMessages {
+     static String systemHealthStatus() {
+       // collect system health information
+       ...
+     }
+   }
+   ...
+   logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
+</code></pre>
+ * With the above code, the health status is collected unnecessarily even when
+ * the log level FINER is disabled. With the Supplier-accepting version as
+ * below, the status will only be collected when the log level FINER is
+ * enabled.
+ <pre><code>
+
+   logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
+</code></pre>
+ * <p>
+ * When looking for a {@code ResourceBundle}, the logger will first look at
+ * whether a bundle was specified using {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
+ * only whether a resource bundle name was specified through the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * If no {@code ResourceBundle} or no resource bundle name is found,
+ * then it will use the nearest {@code ResourceBundle} or resource bundle
+ * name inherited from its parent tree.<br>
+ * When a {@code ResourceBundle} was inherited or specified through the
+ * {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
+ * that {@code ResourceBundle} will be used. Otherwise if the logger only
+ * has or inherited a resource bundle name, then that resource bundle name
+ * will be mapped to a {@code ResourceBundle} object, using the default Locale
+ * at the time of logging.
+ * <br id="ResourceBundleMapping">When mapping resource bundle names to
+ * {@code ResourceBundle} objects, the logger will first try to use the
+ * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
+ * loader} to map the given resource bundle name to a {@code ResourceBundle}.
+ * If the thread context class loader is {@code null}, it will try the
+ * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
+ * instead.  If the {@code ResourceBundle} is still not found, it will use the
+ * class loader of the first caller of the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * <p>
+ * Formatting (including localization) is the responsibility of
+ * the output Handler, which will typically call a Formatter.
+ * <p>
+ * Note that formatting need not occur synchronously.  It may be delayed
+ * until a LogRecord is actually written to an external sink.
+ * <p>
+ * The logging methods are grouped in five main categories:
+ * <ul>
+ * <li><p>
+ *     There are a set of "log" methods that take a log level, a message
+ *     string, and optionally some parameters to the message string.
+ * <li><p>
+ *     There are a set of "logp" methods (for "log precise") that are
+ *     like the "log" methods, but also take an explicit source class name
+ *     and method name.
+ * <li><p>
+ *     There are a set of "logrb" method (for "log with resource bundle")
+ *     that are like the "logp" method, but also take an explicit resource
+ *     bundle object for use in localizing the log message.
+ * <li><p>
+ *     There are convenience methods for tracing method entries (the
+ *     "entering" methods), method returns (the "exiting" methods) and
+ *     throwing exceptions (the "throwing" methods).
+ * <li><p>
+ *     Finally, there are a set of convenience methods for use in the
+ *     very simplest cases, when a developer simply wants to log a
+ *     simple string at a given log level.  These methods are named
+ *     after the standard Level names ("severe", "warning", "info", etc.)
+ *     and take a single argument, a message string.
+ * </ul>
+ * <p>
+ * For the methods that do not take an explicit source name and
+ * method name, the Logging framework will make a "best effort"
+ * to determine which class and method called into the logging method.
+ * However, it is important to realize that this automatically inferred
+ * information may only be approximate (or may even be quite wrong!).
+ * Virtual machines are allowed to do extensive optimizations when
+ * JITing and may entirely remove stack frames, making it impossible
+ * to reliably locate the calling class and method.
+ * <P>
+ * All methods on Logger are multi-thread safe.
+ * <p>
+ * <b>Subclassing Information:</b> Note that a LogManager class may
+ * provide its own implementation of named Loggers for any point in
+ * the namespace.  Therefore, any subclasses of Logger (unless they
+ * are implemented in conjunction with a new LogManager class) should
+ * take care to obtain a Logger instance from the LogManager class and
+ * should delegate operations such as "isLoggable" and "log(LogRecord)"
+ * to that instance.  Note that in order to intercept all logging
+ * output, subclasses need only override the log(LogRecord) method.
+ * All the other logging methods are implemented as calls on this
+ * log(LogRecord) method.
+ *
+ * @since 1.4
+ */
+public class Logger {
+    private static final Handler emptyHandlers[] = new Handler[0];
+    private static final int offValue = Level.OFF.intValue();
+
+    static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
+
+    // This class is immutable and it is important that it remains so.
+    private static final class LoggerBundle {
+        final String resourceBundleName; // Base name of the bundle.
+        final ResourceBundle userBundle; // Bundle set through setResourceBundle.
+        private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
+            this.resourceBundleName = resourceBundleName;
+            this.userBundle = bundle;
+        }
+        boolean isSystemBundle() {
+            return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
+        }
+        static LoggerBundle get(String name, ResourceBundle bundle) {
+            if (name == null && bundle == null) {
+                return NO_RESOURCE_BUNDLE;
+            } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
+                return SYSTEM_BUNDLE;
+            } else {
+                return new LoggerBundle(name, bundle);
+            }
+        }
+    }
+
+    // This instance will be shared by all loggers created by the system
+    // code
+    private static final LoggerBundle SYSTEM_BUNDLE =
+            new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
+
+    // This instance indicates that no resource bundle has been specified yet,
+    // and it will be shared by all loggers which have no resource bundle.
+    private static final LoggerBundle NO_RESOURCE_BUNDLE =
+            new LoggerBundle(null, null);
+
+    private volatile LogManager manager;
+    private String name;
+    private final CopyOnWriteArrayList<Handler> handlers =
+        new CopyOnWriteArrayList<>();
+    private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
+    private volatile boolean useParentHandlers = true;
+    private volatile Filter filter;
+    private boolean anonymous;
+
+    // Cache to speed up behavior of findResourceBundle:
+    private ResourceBundle catalog;     // Cached resource bundle
+    private String catalogName;         // name associated with catalog
+    private Locale catalogLocale;       // locale associated with catalog
+
+    // The fields relating to parent-child relationships and levels
+    // are managed under a separate lock, the treeLock.
+    private static final Object treeLock = new Object();
+    // We keep weak references from parents to children, but strong
+    // references from children to parents.
+    private volatile Logger parent;    // our nearest parent.
+    private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
+    private volatile Level levelObject;
+    private volatile int levelValue;  // current effective level value
+    private WeakReference<ClassLoader> callersClassLoaderRef;
+    private final boolean isSystemLogger;
+
+    /**
+     * GLOBAL_LOGGER_NAME is a name for the global logger.
+     *
+     * @since 1.6
+     */
+    public static final String GLOBAL_LOGGER_NAME = "global";
+
+    /**
+     * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
+     *
+     * @return global logger object
+     * @since 1.7
+     */
+    public static final Logger getGlobal() {
+        // In order to break a cyclic dependence between the LogManager
+        // and Logger static initializers causing deadlocks, the global
+        // logger is created with a special constructor that does not
+        // initialize its log manager.
+        //
+        // If an application calls Logger.getGlobal() before any logger
+        // has been initialized, it is therefore possible that the
+        // LogManager class has not been initialized yet, and therefore
+        // Logger.global.manager will be null.
+        //
+        // In order to finish the initialization of the global logger, we
+        // will therefore call LogManager.getLogManager() here.
+        //
+        // To prevent race conditions we also need to call
+        // LogManager.getLogManager() unconditionally here.
+        // Indeed we cannot rely on the observed value of global.manager,
+        // because global.manager will become not null somewhere during
+        // the initialization of LogManager.
+        // If two threads are calling getGlobal() concurrently, one thread
+        // will see global.manager null and call LogManager.getLogManager(),
+        // but the other thread could come in at a time when global.manager
+        // is already set although ensureLogManagerInitialized is not finished
+        // yet...
+        // Calling LogManager.getLogManager() unconditionally will fix that.
+
+        LogManager.getLogManager();
+
+        // Now the global LogManager should be initialized,
+        // and the global logger should have been added to
+        // it, unless we were called within the constructor of a LogManager
+        // subclass installed as LogManager, in which case global.manager
+        // would still be null, and global will be lazily initialized later on.
+
+        return global;
+    }
+
+    /**
+     * The "global" Logger object is provided as a convenience to developers
+     * who are making casual use of the Logging package.  Developers
+     * who are making serious use of the logging package (for example
+     * in products) should create and use their own Logger objects,
+     * with appropriate names, so that logging can be controlled on a
+     * suitable per-Logger granularity. Developers also need to keep a
+     * strong reference to their Logger objects to prevent them from
+     * being garbage collected.
+     * <p>
+     * @deprecated Initialization of this field is prone to deadlocks.
+     * The field must be initialized by the Logger class initialization
+     * which may cause deadlocks with the LogManager class initialization.
+     * In such cases two class initialization wait for each other to complete.
+     * The preferred way to get the global logger object is via the call
+     * <code>Logger.getGlobal()</code>.
+     * For compatibility with old JDK versions where the
+     * <code>Logger.getGlobal()</code> is not available use the call
+     * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
+     * or <code>Logger.getLogger("global")</code>.
+     */
+    @Deprecated
+    public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
+
+    /**
+     * Protected method to construct a logger for a named subsystem.
+     * <p>
+     * The logger will be initially configured with a null Level
+     * and with useParentHandlers set to true.
+     *
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing.  It may be null for anonymous Loggers.
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.  May be null if none
+     *                          of the messages require localization.
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+    protected Logger(String name, String resourceBundleName) {
+        this(name, resourceBundleName, null, LogManager.getLogManager(), false);
+    }
+
+    Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) {
+        this.manager = manager;
+        this.isSystemLogger = isSystemLogger;
+        setupResourceInfo(resourceBundleName, caller);
+        this.name = name;
+        levelValue = Level.INFO.intValue();
+    }
+
+    private void setCallersClassLoaderRef(Class<?> caller) {
+        ClassLoader callersClassLoader = ((caller != null)
+                                         ? caller.getClassLoader()
+                                         : null);
+        if (callersClassLoader != null) {
+            this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
+        }
+    }
+
+    private ClassLoader getCallersClassLoader() {
+        return (callersClassLoaderRef != null)
+                ? callersClassLoaderRef.get()
+                : null;
+    }
+
+    // This constructor is used only to create the global Logger.
+    // It is needed to break a cyclic dependence between the LogManager
+    // and Logger static initializers causing deadlocks.
+    private Logger(String name) {
+        // The manager field is not initialized here.
+        this.name = name;
+        this.isSystemLogger = true;
+        levelValue = Level.INFO.intValue();
+    }
+
+    // It is called from LoggerContext.addLocalLogger() when the logger
+    // is actually added to a LogManager.
+    void setLogManager(LogManager manager) {
+        this.manager = manager;
+    }
+
+    private void checkPermission() throws SecurityException {
+        if (!anonymous) {
+            if (manager == null) {
+                // Complete initialization of the global Logger.
+                manager = LogManager.getLogManager();
+            }
+            manager.checkPermission();
+        }
+    }
+
+    // Until all JDK code converted to call sun.util.logging.PlatformLogger
+    // (see 7054233), we need to determine if Logger.getLogger is to add
+    // a system logger or user logger.
+    //
+    // As an interim solution, if the immediate caller whose caller loader is
+    // null, we assume it's a system logger and add it to the system context.
+    // These system loggers only set the resource bundle to the given
+    // resource bundle name (rather than the default system resource bundle).
+    private static class SystemLoggerHelper {
+        static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
+        private static boolean getBooleanProperty(final String key) {
+            String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return System.getProperty(key);
+                }
+            });
+            return Boolean.valueOf(s);
+        }
+    }
+
+    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        LogManager manager = LogManager.getLogManager();
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
+            if (caller.getClassLoader() == null) {
+                return manager.demandSystemLogger(name, resourceBundleName);
+            }
+        }
+        return manager.demandLogger(name, resourceBundleName, caller);
+        // ends up calling new Logger(name, resourceBundleName, caller)
+        // iff the logger doesn't exist already
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager configuration and it will configured
+     * to also send logging output to its parent's Handlers.  It will
+     * be registered in the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger").log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     *
+     * @param   name            A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @return a suitable Logger
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name) {
+        // This method is intentionally not a wrapper around a call
+        // to getLogger(name, resourceBundleName). If it were then
+        // this sequence:
+        //
+        //     getLogger("Foo", "resourceBundleForFoo");
+        //     getLogger("Foo");
+        //
+        // would throw an IllegalArgumentException in the second call
+        // because the wrapper would result in an attempt to replace
+        // the existing "resourceBundleForFoo" with null.
+        return demandLogger(name, null, Reflection.getCallerClass());
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager and it will configured to also send logging
+     * output to its parent's Handlers.  It will be registered in
+     * the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     * <p>
+     * If the named Logger already exists and does not yet have a
+     * localization resource bundle then the given resource bundle
+     * name is used.  If the named Logger already exists and has
+     * a different resource bundle name then an IllegalArgumentException
+     * is thrown.
+     * <p>
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger. May be {@code null}
+     *                          if none of the messages require localization.
+     * @return a suitable Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     * @throws IllegalArgumentException if the Logger already exists and uses
+     *             a different resource bundle name; or if
+     *             {@code resourceBundleName} is {@code null} but the named
+     *             logger has a resource bundle set.
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name, String resourceBundleName) {
+        Class<?> callerClass = Reflection.getCallerClass();
+        Logger result = demandLogger(name, resourceBundleName, callerClass);
+
+        // MissingResourceException or IllegalArgumentException can be
+        // thrown by setupResourceInfo().
+        // We have to set the callers ClassLoader here in case demandLogger
+        // above found a previously created Logger.  This can happen, for
+        // example, if Logger.getLogger(name) is called and subsequently
+        // Logger.getLogger(name, resourceBundleName) is called.  In this case
+        // we won't necessarily have the correct classloader saved away, so
+        // we need to set it here, too.
+
+        result.setupResourceInfo(resourceBundleName, callerClass);
+        return result;
+    }
+
+    // package-private
+    // Add a platform logger to the system context.
+    // i.e. caller of sun.util.logging.PlatformLogger.getLogger
+    static Logger getPlatformLogger(String name) {
+        LogManager manager = LogManager.getLogManager();
+
+        // all loggers in the system context will default to
+        // the system logger's resource bundle
+        Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
+        return result;
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger. Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     *
+     * @return a newly created private Logger
+     */
+    public static Logger getAnonymousLogger() {
+        return getAnonymousLogger(null);
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger.  Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.
+     *          May be null if none of the messages require localization.
+     * @return a newly created private Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new anonymous Logger object is handled by doSetParent().
+    @CallerSensitive
+    public static Logger getAnonymousLogger(String resourceBundleName) {
+        LogManager manager = LogManager.getLogManager();
+        // cleanup some Loggers that have been GC'ed
+        manager.drainLoggerRefQueueBounded();
+        Logger result = new Logger(null, resourceBundleName,
+                                   Reflection.getCallerClass(), manager, false);
+        result.anonymous = true;
+        Logger root = manager.getLogger("");
+        result.doSetParent(root);
+        return result;
+    }
+
+    /**
+     * Retrieve the localization resource bundle for this
+     * logger.
+     * This method will return a {@code ResourceBundle} that was either
+     * set by the {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
+     * <a href="#ResourceBundleMapping">mapped from the
+     * the resource bundle name</a> set via the {@link
+     * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
+     * method for the current default locale.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle (may be {@code null})
+     */
+    public ResourceBundle getResourceBundle() {
+        return findResourceBundle(getResourceBundleName(), true);
+    }
+
+    /**
+     * Retrieve the localization resource bundle name for this
+     * logger.
+     * This is either the name specified through the {@link
+     * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
+     * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
+     * ResourceBundle set through {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle name (may be {@code null})
+     */
+    public String getResourceBundleName() {
+        return loggerBundle.resourceBundleName;
+    }
+
+    /**
+     * Set a filter to control output on this Logger.
+     * <P>
+     * After passing the initial "level" check, the Logger will
+     * call this Filter to check if a log record should really
+     * be published.
+     *
+     * @param   newFilter  a filter object (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current filter for this Logger.
+     *
+     * @return  a filter object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Log a LogRecord.
+     * <p>
+     * All the other logging methods in this class call through
+     * this method to actually perform any logging.  Subclasses can
+     * override this single method to capture all log activity.
+     *
+     * @param record the LogRecord to be published
+     */
+    public void log(LogRecord record) {
+        if (!isLoggable(record.getLevel())) {
+            return;
+        }
+        Filter theFilter = filter;
+        if (theFilter != null && !theFilter.isLoggable(record)) {
+            return;
+        }
+
+        // Post the LogRecord to all our Handlers, and then to
+        // our parents' handlers, all the way up the tree.
+
+        Logger logger = this;
+        while (logger != null) {
+            final Handler[] loggerHandlers = isSystemLogger
+                ? logger.accessCheckedHandlers()
+                : logger.getHandlers();
+
+            for (Handler handler : loggerHandlers) {
+                handler.publish(record);
+            }
+
+            final boolean useParentHdls = isSystemLogger
+                ? logger.useParentHandlers
+                : logger.getUseParentHandlers();
+
+            if (!useParentHdls) {
+                break;
+            }
+
+            logger = isSystemLogger ? logger.parent : logger.getParent();
+        }
+    }
+
+    // private support method for logging.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr) {
+        lr.setLoggerName(name);
+        final LoggerBundle lb = getEffectiveLoggerBundle();
+        final ResourceBundle  bundle = lb.userBundle;
+        final String ebname = lb.resourceBundleName;
+        if (ebname != null && bundle != null) {
+            lr.setResourceBundleName(ebname);
+            lr.setResourceBundle(bundle);
+        }
+        log(lr);
+    }
+
+
+    //================================================================
+    // Start of convenience methods WITHOUT className and methodName
+    //================================================================
+
+    /**
+     * Log a message, with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void log(Level level, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, which is only to be constructed if the logging level
+     * is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since 1.8
+     */
+    public void log(Level level, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with one object parameter.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   param1  parameter to the message
+     */
+    public void log(Level level, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  array of parameters to the message
+     */
+    public void log(Level level, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void log(Level level, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //================================================================
+    // Start of convenience methods WITH className and methodName
+    //================================================================
+
+    /**
+     * Log a message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+
+    //=========================================================================
+    // Start of convenience methods WITH className, methodName and bundle name.
+    //=========================================================================
+
+    // Private support method for logging for "logrb" methods.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr, String rbname) {
+        lr.setLoggerName(name);
+        if (rbname != null) {
+            lr.setResourceBundleName(rbname);
+            lr.setResourceBundle(findResourceBundle(rbname, false));
+        }
+        log(lr);
+    }
+
+    // Private support method for logging for "logrb" methods.
+    private void doLog(LogRecord lr, ResourceBundle rb) {
+        lr.setLoggerName(name);
+        if (rb != null) {
+            lr.setResourceBundleName(rb.getBaseBundleName());
+            lr.setResourceBundle(rb);
+        }
+        log(lr);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     * java.lang.String, java.util.ResourceBundle, java.lang.String,
+     * java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *   java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *   java.lang.Object...)} instead
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *      java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *      java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with an optional list of message parameters.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Parameters to the message (optional, may be none).
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Object... params) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        if (params != null && params.length != 0) {
+            lr.setParameters(params);
+        }
+        doLog(lr, bundle);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *     java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *     java.lang.Throwable)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                        String bundleName, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with the log message.
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundle);
+    }
+
+    //======================================================================
+    // Start of convenience methods for logging method entries and returns.
+    //======================================================================
+
+    /**
+     * Log a method entry.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     */
+    public void entering(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+    }
+
+    /**
+     * Log a method entry, with one parameter.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY {0}", log level
+     * FINER, and the given sourceMethod, sourceClass, and parameter
+     * is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   param1         parameter to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object param1) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
+    }
+
+    /**
+     * Log a method entry, with an array of parameters.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY" (followed by a
+     * format {N} indicator for each entry in the parameter array),
+     * log level FINER, and the given sourceMethod, sourceClass, and
+     * parameters is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   params         array of parameters to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object params[]) {
+        String msg = "ENTRY";
+        if (params == null ) {
+           logp(Level.FINER, sourceClass, sourceMethod, msg);
+           return;
+        }
+        if (!isLoggable(Level.FINER)) return;
+        for (int i = 0; i < params.length; i++) {
+            msg = msg + " {" + i + "}";
+        }
+        logp(Level.FINER, sourceClass, sourceMethod, msg, params);
+    }
+
+    /**
+     * Log a method return.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     */
+    public void exiting(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+    }
+
+
+    /**
+     * Log a method return, with result object.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN {0}", log level
+     * FINER, and the gives sourceMethod, sourceClass, and result
+     * object is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     * @param   result  Object that is being returned
+     */
+    public void exiting(String sourceClass, String sourceMethod, Object result) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
+    }
+
+    /**
+     * Log throwing an exception.
+     * <p>
+     * This is a convenience method to log that a method is
+     * terminating by throwing an exception.  The logging is done
+     * using the FINER level.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.  The
+     * LogRecord's message is set to "THROW".
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod  name of the method.
+     * @param   thrown  The Throwable that is being thrown.
+     */
+    public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
+        if (!isLoggable(Level.FINER)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(Level.FINER, "THROW");
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void severe(String msg) {
+        log(Level.SEVERE, msg);
+    }
+
+    /**
+     * Log a WARNING message.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void warning(String msg) {
+        log(Level.WARNING, msg);
+    }
+
+    /**
+     * Log an INFO message.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void info(String msg) {
+        log(Level.INFO, msg);
+    }
+
+    /**
+     * Log a CONFIG message.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void config(String msg) {
+        log(Level.CONFIG, msg);
+    }
+
+    /**
+     * Log a FINE message.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void fine(String msg) {
+        log(Level.FINE, msg);
+    }
+
+    /**
+     * Log a FINER message.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finer(String msg) {
+        log(Level.FINER, msg);
+    }
+
+    /**
+     * Log a FINEST message.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finest(String msg) {
+        log(Level.FINEST, msg);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    // and use Supplier<String>
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void severe(Supplier<String> msgSupplier) {
+        log(Level.SEVERE, msgSupplier);
+    }
+
+    /**
+     * Log a WARNING message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void warning(Supplier<String> msgSupplier) {
+        log(Level.WARNING, msgSupplier);
+    }
+
+    /**
+     * Log a INFO message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void info(Supplier<String> msgSupplier) {
+        log(Level.INFO, msgSupplier);
+    }
+
+    /**
+     * Log a CONFIG message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void config(Supplier<String> msgSupplier) {
+        log(Level.CONFIG, msgSupplier);
+    }
+
+    /**
+     * Log a FINE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void fine(Supplier<String> msgSupplier) {
+        log(Level.FINE, msgSupplier);
+    }
+
+    /**
+     * Log a FINER message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finer(Supplier<String> msgSupplier) {
+        log(Level.FINER, msgSupplier);
+    }
+
+    /**
+     * Log a FINEST message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finest(Supplier<String> msgSupplier) {
+        log(Level.FINEST, msgSupplier);
+    }
+
+    //================================================================
+    // End of convenience methods
+    //================================================================
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this logger.  Message levels lower than this
+     * value will be discarded.  The level value Level.OFF
+     * can be used to turn off logging.
+     * <p>
+     * If the new level is null, it means that this node should
+     * inherit its level from its nearest ancestor with a specific
+     * (non-null) level value.
+     *
+     * @param newLevel   the new value for the log level (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setLevel(Level newLevel) throws SecurityException {
+        checkPermission();
+        synchronized (treeLock) {
+            levelObject = newLevel;
+            updateEffectiveLevel();
+        }
+    }
+
+    final boolean isLevelInitialized() {
+        return levelObject != null;
+    }
+
+    /**
+     * Get the log Level that has been specified for this Logger.
+     * The result may be null, which means that this logger's
+     * effective level will be inherited from its parent.
+     *
+     * @return  this Logger's level
+     */
+    public Level getLevel() {
+        return levelObject;
+    }
+
+    /**
+     * Check if a message of the given level would actually be logged
+     * by this logger.  This check is based on the Loggers effective level,
+     * which may be inherited from its parent.
+     *
+     * @param   level   a message logging level
+     * @return  true if the given message level is currently being logged.
+     */
+    public boolean isLoggable(Level level) {
+        if (level.intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get the name for this logger.
+     * @return logger name.  Will be null for anonymous Loggers.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Add a log Handler to receive logging messages.
+     * <p>
+     * By default, Loggers also send their output to their parent logger.
+     * Typically the root Logger is configured with a set of Handlers
+     * that essentially act as default handlers for all loggers.
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void addHandler(Handler handler) throws SecurityException {
+        // Check for null handler
+        handler.getClass();
+        checkPermission();
+        handlers.add(handler);
+    }
+
+    /**
+     * Remove a log Handler.
+     * <P>
+     * Returns silently if the given Handler is not found or is null
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void removeHandler(Handler handler) throws SecurityException {
+        checkPermission();
+        if (handler == null) {
+            return;
+        }
+        handlers.remove(handler);
+    }
+
+    /**
+     * Get the Handlers associated with this logger.
+     * <p>
+     * @return  an array of all registered Handlers
+     */
+    public Handler[] getHandlers() {
+        return accessCheckedHandlers();
+    }
+
+    // This method should ideally be marked final - but unfortunately
+    // it needs to be overridden by LogManager.RootLogger
+    Handler[] accessCheckedHandlers() {
+        return handlers.toArray(emptyHandlers);
+    }
+
+    /**
+     * Specify whether or not this logger should send its output
+     * to its parent Logger.  This means that any LogRecords will
+     * also be written to the parent's Handlers, and potentially
+     * to its parent, recursively up the namespace.
+     *
+     * @param useParentHandlers   true if output is to be sent to the
+     *          logger's parent.
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setUseParentHandlers(boolean useParentHandlers) {
+        checkPermission();
+        this.useParentHandlers = useParentHandlers;
+    }
+
+    /**
+     * Discover whether or not this logger is sending its output
+     * to its parent logger.
+     *
+     * @return  true if output is to be sent to the logger's parent
+     */
+    public boolean getUseParentHandlers() {
+        return useParentHandlers;
+    }
+
+    private static ResourceBundle findSystemResourceBundle(final Locale locale) {
+        // the resource bundle is in a restricted package
+        return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
+            @Override
+            public ResourceBundle run() {
+                try {
+                    return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
+                                                    locale,
+                                                    ClassLoader.getSystemClassLoader());
+                } catch (MissingResourceException e) {
+                    throw new InternalError(e.toString());
+                }
+            }
+        });
+    }
+
+    /**
+     * Private utility method to map a resource bundle name to an
+     * actual resource bundle, using a simple one-entry cache.
+     * Returns null for a null name.
+     * May also return null if we can't find the resource bundle and
+     * there is no suitable previous cached value.
+     *
+     * @param name the ResourceBundle to locate
+     * @param userCallersClassLoader if true search using the caller's ClassLoader
+     * @return ResourceBundle specified by name or null if not found
+     */
+    private synchronized ResourceBundle findResourceBundle(String name,
+                                                           boolean useCallersClassLoader) {
+        // For all lookups, we first check the thread context class loader
+        // if it is set.  If not, we use the system classloader.  If we
+        // still haven't found it we use the callersClassLoaderRef if it
+        // is set and useCallersClassLoader is true.  We set
+        // callersClassLoaderRef initially upon creating the logger with a
+        // non-null resource bundle name.
+
+        // Return a null bundle for a null name.
+        if (name == null) {
+            return null;
+        }
+
+        Locale currentLocale = Locale.getDefault();
+        final LoggerBundle lb = loggerBundle;
+
+        // Normally we should hit on our simple one entry cache.
+        if (lb.userBundle != null &&
+                name.equals(lb.resourceBundleName)) {
+            return lb.userBundle;
+        } else if (catalog != null && currentLocale.equals(catalogLocale)
+                && name.equals(catalogName)) {
+            return catalog;
+        }
+
+        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
+            catalog = findSystemResourceBundle(currentLocale);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        }
+
+        // Use the thread's context ClassLoader.  If there isn't one, use the
+        // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+        try {
+            catalog = ResourceBundle.getBundle(name, currentLocale, cl);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        } catch (MissingResourceException ex) {
+            // We can't find the ResourceBundle in the default
+            // ClassLoader.  Drop through.
+        }
+
+        if (useCallersClassLoader) {
+            // Try with the caller's ClassLoader
+            ClassLoader callersClassLoader = getCallersClassLoader();
+
+            if (callersClassLoader == null || callersClassLoader == cl) {
+                return null;
+            }
+
+            try {
+                catalog = ResourceBundle.getBundle(name, currentLocale,
+                                                   callersClassLoader);
+                catalogName = name;
+                catalogLocale = currentLocale;
+                return catalog;
+            } catch (MissingResourceException ex) {
+                return null; // no luck
+            }
+        } else {
+            return null;
+        }
+    }
+
+    // Private utility method to initialize our one entry
+    // resource bundle name cache and the callers ClassLoader
+    // Note: for consistency reasons, we are careful to check
+    // that a suitable ResourceBundle exists before setting the
+    // resourceBundleName field.
+    // Synchronized to prevent races in setting the fields.
+    private synchronized void setupResourceInfo(String name,
+                                                Class<?> callersClass) {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.resourceBundleName != null) {
+            // this Logger already has a ResourceBundle
+
+            if (lb.resourceBundleName.equals(name)) {
+                // the names match so there is nothing more to do
+                return;
+            }
+
+            // cannot change ResourceBundles once they are set
+            throw new IllegalArgumentException(
+                lb.resourceBundleName + " != " + name);
+        }
+
+        if (name == null) {
+            return;
+        }
+
+        setCallersClassLoaderRef(callersClass);
+        if (isSystemLogger && getCallersClassLoader() != null) {
+            checkPermission();
+        }
+        if (findResourceBundle(name, true) == null) {
+            // We've failed to find an expected ResourceBundle.
+            // unset the caller's ClassLoader since we were unable to find the
+            // the bundle using it
+            this.callersClassLoaderRef = null;
+            throw new MissingResourceException("Can't find " + name + " bundle",
+                                                name, "");
+        }
+
+        // if lb.userBundle is not null we won't reach this line.
+        assert lb.userBundle == null;
+        loggerBundle = LoggerBundle.get(name, null);
+    }
+
+    /**
+     * Sets a resource bundle on this logger.
+     * All messages will be logged using the given resource bundle for its
+     * specific {@linkplain ResourceBundle#getLocale locale}.
+     * @param bundle The resource bundle that this logger shall use.
+     * @throws NullPointerException if the given bundle is {@code null}.
+     * @throws IllegalArgumentException if the given bundle doesn't have a
+     *         {@linkplain ResourceBundle#getBaseBundleName base name},
+     *         or if this logger already has a resource bundle set but
+     *         the given bundle has a different base name.
+     * @throws SecurityException if a security manager exists,
+     *         this logger is not anonymous, and the caller
+     *         does not have LoggingPermission("control").
+     * @since 1.8
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        checkPermission();
+
+        // Will throw NPE if bundle is null.
+        final String baseName = bundle.getBaseBundleName();
+
+        // bundle must have a name
+        if (baseName == null || baseName.isEmpty()) {
+            throw new IllegalArgumentException("resource bundle must have a name");
+        }
+
+        synchronized (this) {
+            LoggerBundle lb = loggerBundle;
+            final boolean canReplaceResourceBundle = lb.resourceBundleName == null
+                    || lb.resourceBundleName.equals(baseName);
+
+            if (!canReplaceResourceBundle) {
+                throw new IllegalArgumentException("can't replace resource bundle");
+            }
+
+
+            loggerBundle = LoggerBundle.get(baseName, bundle);
+        }
+    }
+
+    /**
+     * Return the parent for this Logger.
+     * <p>
+     * This method returns the nearest extant parent in the namespace.
+     * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
+     * has been created but no logger "a.b.c" exists, then a call of
+     * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
+     * <p>
+     * The result will be null if it is called on the root Logger
+     * in the namespace.
+     *
+     * @return nearest existing parent Logger
+     */
+    public Logger getParent() {
+        // Note: this used to be synchronized on treeLock.  However, this only
+        // provided memory semantics, as there was no guarantee that the caller
+        // would synchronize on treeLock (in fact, there is no way for external
+        // callers to so synchronize).  Therefore, we have made parent volatile
+        // instead.
+        return parent;
+    }
+
+    /**
+     * Set the parent for this Logger.  This method is used by
+     * the LogManager to update a Logger when the namespace changes.
+     * <p>
+     * It should not be called from application code.
+     * <p>
+     * @param  parent   the new parent logger
+     * @throws  SecurityException  if a security manager exists and if
+     *          the caller does not have LoggingPermission("control").
+     */
+    public void setParent(Logger parent) {
+        if (parent == null) {
+            throw new NullPointerException();
+        }
+
+        // check permission for all loggers, including anonymous loggers
+        if (manager == null) {
+            manager = LogManager.getLogManager();
+        }
+        manager.checkPermission();
+
+        doSetParent(parent);
+    }
+
+    // Private method to do the work for parenting a child
+    // Logger onto a parent logger.
+    private void doSetParent(Logger newParent) {
+
+        // System.err.println("doSetParent \"" + getName() + "\" \""
+        //                              + newParent.getName() + "\"");
+
+        synchronized (treeLock) {
+
+            // Remove ourself from any previous parent.
+            LogManager.LoggerWeakRef ref = null;
+            if (parent != null) {
+                // assert parent.kids != null;
+                for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
+                    ref = iter.next();
+                    Logger kid =  ref.get();
+                    if (kid == this) {
+                        // ref is used down below to complete the reparenting
+                        iter.remove();
+                        break;
+                    } else {
+                        ref = null;
+                    }
+                }
+                // We have now removed ourself from our parents' kids.
+            }
+
+            // Set our new parent.
+            parent = newParent;
+            if (parent.kids == null) {
+                parent.kids = new ArrayList<>(2);
+            }
+            if (ref == null) {
+                // we didn't have a previous parent
+                ref = manager.new LoggerWeakRef(this);
+            }
+            ref.setParentRef(new WeakReference<>(parent));
+            parent.kids.add(ref);
+
+            // As a result of the reparenting, the effective level
+            // may have changed for us and our children.
+            updateEffectiveLevel();
+
+        }
+    }
+
+    // Package-level method.
+    // Remove the weak reference for the specified child Logger from the
+    // kid list. We should only be called from LoggerWeakRef.dispose().
+    final void removeChildLogger(LogManager.LoggerWeakRef child) {
+        synchronized (treeLock) {
+            for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
+                LogManager.LoggerWeakRef ref = iter.next();
+                if (ref == child) {
+                    iter.remove();
+                    return;
+                }
+            }
+        }
+    }
+
+    // Recalculate the effective level for this node and
+    // recursively for our children.
+
+    private void updateEffectiveLevel() {
+        // assert Thread.holdsLock(treeLock);
+
+        // Figure out our current effective level.
+        int newLevelValue;
+        if (levelObject != null) {
+            newLevelValue = levelObject.intValue();
+        } else {
+            if (parent != null) {
+                newLevelValue = parent.levelValue;
+            } else {
+                // This may happen during initialization.
+                newLevelValue = Level.INFO.intValue();
+            }
+        }
+
+        // If our effective value hasn't changed, we're done.
+        if (levelValue == newLevelValue) {
+            return;
+        }
+
+        levelValue = newLevelValue;
+
+        // System.err.println("effective level: \"" + getName() + "\" := " + level);
+
+        // Recursively update the level on each of our kids.
+        if (kids != null) {
+            for (int i = 0; i < kids.size(); i++) {
+                LogManager.LoggerWeakRef ref = kids.get(i);
+                Logger kid =  ref.get();
+                if (kid != null) {
+                    kid.updateEffectiveLevel();
+                }
+            }
+        }
+    }
+
+
+    // Private method to get the potentially inherited
+    // resource bundle and resource bundle name for this Logger.
+    // This method never returns null.
+    private LoggerBundle getEffectiveLoggerBundle() {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.isSystemBundle()) {
+            return SYSTEM_BUNDLE;
+        }
+
+        // first take care of this logger
+        final ResourceBundle b = getResourceBundle();
+        if (b != null && b == lb.userBundle) {
+            return lb;
+        } else if (b != null) {
+            // either lb.userBundle is null or getResourceBundle() is
+            // overriden
+            final String rbName = getResourceBundleName();
+            return LoggerBundle.get(rbName, b);
+        }
+
+        // no resource bundle was specified on this logger, look up the
+        // parent stack.
+        Logger target = this.parent;
+        while (target != null) {
+            final LoggerBundle trb = target.loggerBundle;
+            if (trb.isSystemBundle()) {
+                return SYSTEM_BUNDLE;
+            }
+            if (trb.userBundle != null) {
+                return trb;
+            }
+            final String rbName = isSystemLogger
+                // ancestor of a system logger is expected to be a system logger.
+                // ignore resource bundle name if it's not.
+                ? (target.isSystemLogger ? trb.resourceBundleName : null)
+                : target.getResourceBundleName();
+            if (rbName != null) {
+                return LoggerBundle.get(rbName,
+                        findResourceBundle(rbName, true));
+            }
+            target = isSystemLogger ? target.parent : target.getParent();
+        }
+        return NO_RESOURCE_BUNDLE;
+    }
+
+}
diff --git a/android-35/java/util/logging/Logging.java b/android-35/java/util/logging/Logging.java
new file mode 100644
index 0000000..740a533
--- /dev/null
+++ b/android-35/java/util/logging/Logging.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Logging is the implementation class of LoggingMXBean.
+ *
+ * The <tt>LoggingMXBean</tt> interface provides a standard
+ * method for management access to the individual
+ * {@code Logger} objects available at runtime.
+ *
+ * @author Ron Mann
+ * @author Mandy Chung
+ * @since 1.5
+ *
+ * @see javax.management
+ * @see Logger
+ * @see LogManager
+ */
+class Logging implements LoggingMXBean {
+
+    private static LogManager logManager = LogManager.getLogManager();
+
+    /** Constructor of Logging which is the implementation class
+     *  of LoggingMXBean.
+     */
+    Logging() {
+    }
+
+    public List<String> getLoggerNames() {
+        Enumeration<String> loggers = logManager.getLoggerNames();
+        ArrayList<String> array = new ArrayList<>();
+
+        for (; loggers.hasMoreElements();) {
+            array.add(loggers.nextElement());
+        }
+        return array;
+    }
+
+    private static String EMPTY_STRING = "";
+    public String getLoggerLevel(String loggerName) {
+        Logger l = logManager.getLogger(loggerName);
+        if (l == null) {
+            return null;
+        }
+
+        Level level = l.getLevel();
+        if (level == null) {
+            return EMPTY_STRING;
+        } else {
+            return level.getLevelName();
+        }
+    }
+
+    public void setLoggerLevel(String loggerName, String levelName) {
+        if (loggerName == null) {
+            throw new NullPointerException("loggerName is null");
+        }
+
+        Logger logger = logManager.getLogger(loggerName);
+        if (logger == null) {
+            throw new IllegalArgumentException("Logger " + loggerName +
+                "does not exist");
+        }
+
+        Level level = null;
+        if (levelName != null) {
+            // parse will throw IAE if logLevel is invalid
+            level = Level.findLevel(levelName);
+            if (level == null) {
+                throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+            }
+        }
+
+        logger.setLevel(level);
+    }
+
+    public String getParentLoggerName( String loggerName ) {
+        Logger l = logManager.getLogger( loggerName );
+        if (l == null) {
+            return null;
+        }
+
+        Logger p = l.getParent();
+        if (p == null) {
+            // root logger
+            return EMPTY_STRING;
+        } else {
+            return p.getName();
+        }
+    }
+}
diff --git a/android-35/java/util/logging/LoggingMXBean.java b/android-35/java/util/logging/LoggingMXBean.java
new file mode 100644
index 0000000..14777c0
--- /dev/null
+++ b/android-35/java/util/logging/LoggingMXBean.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+// Android-removed: References to java.lang.management in javadoc.
+
+/**
+ * The management interface for the logging facility.
+ *
+ * <p>There is a single global instance of the <tt>LoggingMXBean</tt>.
+ *
+ * The {@code javax.management.ObjectName ObjectName} that uniquely identifies
+ * the management interface for logging within the {@code MBeanServer} is:
+ * <pre>
+ *    {@link LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging}
+ * </pre>
+ * <p>
+ *
+ * @author  Ron Mann
+ * @author  Mandy Chung
+ * @since   1.5
+ *
+ */
+public interface LoggingMXBean {
+
+    /**
+     * Returns the list of currently registered logger names. This method
+     * calls {@link LogManager#getLoggerNames} and returns a list
+     * of the logger names.
+     *
+     * @return A list of <tt>String</tt> each of which is a
+     *         currently registered <tt>Logger</tt> name.
+     */
+    public java.util.List<String> getLoggerNames();
+
+    /**
+     * Gets the name of the log level associated with the specified logger.
+     * If the specified logger does not exist, <tt>null</tt>
+     * is returned.
+     * This method first finds the logger of the given name and
+     * then returns the name of the log level by calling:
+     * <blockquote>
+     *   {@link Logger#getLevel Logger.getLevel()}.{@link Level#getName getName()};
+     * </blockquote>
+     *
+     * <p>
+     * If the <tt>Level</tt> of the specified logger is <tt>null</tt>,
+     * which means that this logger's effective level is inherited
+     * from its parent, an empty string will be returned.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be retrieved.
+     *
+     * @return The name of the log level of the specified logger; or
+     *         an empty string if the log level of the specified logger
+     *         is <tt>null</tt>.  If the specified logger does not
+     *         exist, <tt>null</tt> is returned.
+     *
+     * @see Logger#getLevel
+     */
+    public String getLoggerLevel(String loggerName);
+
+    /**
+     * Sets the specified logger to the specified new level.
+     * If the <tt>levelName</tt> is not <tt>null</tt>, the level
+     * of the specified logger is set to the parsed <tt>Level</tt>
+     * matching the <tt>levelName</tt>.
+     * If the <tt>levelName</tt> is <tt>null</tt>, the level
+     * of the specified logger is set to <tt>null</tt> and
+     * the effective level of the logger is inherited from
+     * its nearest ancestor with a specific (non-null) level value.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be set.
+     *                   Must be non-null.
+     * @param levelName The name of the level to set on the specified logger,
+     *                 or <tt>null</tt> if setting the level to inherit
+     *                 from its nearest ancestor.
+     *
+     * @throws IllegalArgumentException if the specified logger
+     * does not exist, or <tt>levelName</tt> is not a valid level name.
+     *
+     * @throws SecurityException if a security manager exists and if
+     * the caller does not have LoggingPermission("control").
+     *
+     * @see Logger#setLevel
+     */
+    public void setLoggerLevel(String loggerName, String levelName);
+
+    /**
+     * Returns the name of the parent for the specified logger.
+     * If the specified logger does not exist, <tt>null</tt> is returned.
+     * If the specified logger is the root <tt>Logger</tt> in the namespace,
+     * the result will be an empty string.
+     *
+     * @param loggerName The name of a <tt>Logger</tt>.
+     *
+     * @return the name of the nearest existing parent logger;
+     *         an empty string if the specified logger is the root logger.
+     *         If the specified logger does not exist, <tt>null</tt>
+     *         is returned.
+     */
+    public String getParentLoggerName(String loggerName);
+}
diff --git a/android-35/java/util/logging/LoggingPermission.java b/android-35/java/util/logging/LoggingPermission.java
new file mode 100644
index 0000000..5cea7a5
--- /dev/null
+++ b/android-35/java/util/logging/LoggingPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class LoggingPermission extends java.security.BasicPermission {
+
+    public LoggingPermission(String name, String actions) throws IllegalArgumentException {
+        super("", "");
+    }
+}
diff --git a/android-35/java/util/logging/LoggingProxyImpl.java b/android-35/java/util/logging/LoggingProxyImpl.java
new file mode 100644
index 0000000..61fcb7b
--- /dev/null
+++ b/android-35/java/util/logging/LoggingProxyImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import sun.util.logging.LoggingProxy;
+
+/**
+ * Implementation of LoggingProxy when java.util.logging classes exist.
+ */
+class LoggingProxyImpl implements LoggingProxy {
+    static final LoggingProxy INSTANCE = new LoggingProxyImpl();
+
+    private LoggingProxyImpl() { }
+
+    @Override
+    public Object getLogger(String name) {
+        // always create a platform logger with the resource bundle name
+        return Logger.getPlatformLogger(name);
+    }
+
+    @Override
+    public Object getLevel(Object logger) {
+        return ((Logger) logger).getLevel();
+    }
+
+    @Override
+    public void setLevel(Object logger, Object newLevel) {
+        ((Logger) logger).setLevel((Level) newLevel);
+    }
+
+    @Override
+    public boolean isLoggable(Object logger, Object level) {
+        return ((Logger) logger).isLoggable((Level) level);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg) {
+        ((Logger) logger).log((Level) level, msg);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Throwable t) {
+        ((Logger) logger).log((Level) level, msg, t);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Object... params) {
+        ((Logger) logger).log((Level) level, msg, params);
+    }
+
+    @Override
+    public java.util.List<String> getLoggerNames() {
+        return LogManager.getLoggingMXBean().getLoggerNames();
+    }
+
+    @Override
+    public String getLoggerLevel(String loggerName) {
+        return LogManager.getLoggingMXBean().getLoggerLevel(loggerName);
+    }
+
+    @Override
+    public void setLoggerLevel(String loggerName, String levelName) {
+        LogManager.getLoggingMXBean().setLoggerLevel(loggerName, levelName);
+    }
+
+    @Override
+    public String getParentLoggerName(String loggerName) {
+        return LogManager.getLoggingMXBean().getParentLoggerName(loggerName);
+    }
+
+    @Override
+    public Object parseLevel(String levelName) {
+        Level level = Level.findLevel(levelName);
+        if (level == null) {
+            throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+        }
+        return level;
+    }
+
+    @Override
+    public String getLevelName(Object level) {
+        return ((Level) level).getLevelName();
+    }
+
+    @Override
+    public int getLevelValue(Object level) {
+        return ((Level) level).intValue();
+    }
+
+    @Override
+    public String getProperty(String key) {
+        return LogManager.getLogManager().getProperty(key);
+    }
+}
diff --git a/android-35/java/util/logging/MemoryHandler.java b/android-35/java/util/logging/MemoryHandler.java
new file mode 100644
index 0000000..704c155
--- /dev/null
+++ b/android-35/java/util/logging/MemoryHandler.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+/**
+ * <tt>Handler</tt> that buffers requests in a circular buffer in memory.
+ * <p>
+ * Normally this <tt>Handler</tt> simply stores incoming <tt>LogRecords</tt>
+ * into its memory buffer and discards earlier records.  This buffering
+ * is very cheap and avoids formatting costs.  On certain trigger
+ * conditions, the <tt>MemoryHandler</tt> will push out its current buffer
+ * contents to a target <tt>Handler</tt>, which will typically publish
+ * them to the outside world.
+ * <p>
+ * There are three main models for triggering a push of the buffer:
+ * <ul>
+ * <li>
+ * An incoming <tt>LogRecord</tt> has a type that is greater than
+ * a pre-defined level, the <tt>pushLevel</tt>. </li>
+ * <li>
+ * An external class calls the <tt>push</tt> method explicitly. </li>
+ * <li>
+ * A subclass overrides the <tt>log</tt> method and scans each incoming
+ * <tt>LogRecord</tt> and calls <tt>push</tt> if a record matches some
+ * desired criteria. </li>
+ * </ul>
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>MemoryHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * If no default value is defined then a RuntimeException is thrown.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.size
+ *        defines the buffer size (defaults to 1000). </li>
+ * <li>   &lt;handler-name&gt;.push
+ *        defines the <tt>pushLevel</tt> (defaults to <tt>level.SEVERE</tt>). </li>
+ * <li>   &lt;handler-name&gt;.target
+ *        specifies the name of the target <tt>Handler </tt> class.
+ *        (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code MemoryHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.MemoryHandler.level=INFO </li>
+ * <li>   java.util.logging.MemoryHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class MemoryHandler extends Handler {
+    private final static int DEFAULT_SIZE = 1000;
+    private volatile Level pushLevel;
+    private int size;
+    private Handler target;
+    private LogRecord buffer[];
+    int start, count;
+
+    // Private method to configure a MemoryHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        pushLevel = manager.getLevelProperty(cname +".push", Level.SEVERE);
+        size = manager.getIntProperty(cname + ".size", DEFAULT_SIZE);
+        if (size <= 0) {
+            size = DEFAULT_SIZE;
+        }
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt> and configure it based on
+     * <tt>LogManager</tt> configuration properties.
+     */
+    public MemoryHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+
+        LogManager manager = LogManager.getLogManager();
+        String handlerName = getClass().getName();
+        String targetName = manager.getProperty(handlerName+".target");
+        if (targetName == null) {
+            throw new RuntimeException("The handler " + handlerName
+                    + " does not specify a target");
+        }
+        Class<?> clz;
+        try {
+            clz = ClassLoader.getSystemClassLoader().loadClass(targetName);
+            target = (Handler) clz.newInstance();
+        // Android-changed: Fall back to the context classloader before giving up.
+        // } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+        //     throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e);
+        } catch (Exception e) {
+            try {
+                clz = Thread.currentThread().getContextClassLoader()
+                        .loadClass(targetName);
+                target = (Handler) clz.newInstance();
+            } catch (Exception innerE) {
+                throw new RuntimeException("MemoryHandler can't load handler target \"" +
+                        targetName + "\"" , innerE);
+            }
+        }
+        init();
+    }
+
+    // Initialize.  Size is a count of LogRecords.
+    private void init() {
+        buffer = new LogRecord[size];
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt>.
+     * <p>
+     * The <tt>MemoryHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given <tt>pushLevel</tt>
+     * argument and buffer size argument are used.
+     *
+     * @param target  the Handler to which to publish output.
+     * @param size    the number of log records to buffer (must be greater than zero)
+     * @param pushLevel  message level to push on
+     *
+     * @throws IllegalArgumentException if {@code size is <= 0}
+     */
+    public MemoryHandler(Handler target, int size, Level pushLevel) {
+        if (target == null || pushLevel == null) {
+            throw new NullPointerException();
+        }
+        if (size <= 0) {
+            throw new IllegalArgumentException();
+        }
+        sealed = false;
+        configure();
+        sealed = true;
+        this.target = target;
+        this.pushLevel = pushLevel;
+        this.size = size;
+        init();
+    }
+
+    /**
+     * Store a <tt>LogRecord</tt> in an internal buffer.
+     * <p>
+     * If there is a <tt>Filter</tt>, its <tt>isLoggable</tt>
+     * method is called to check if the given log record is loggable.
+     * If not we return.  Otherwise the given record is copied into
+     * an internal circular buffer.  Then the record's level property is
+     * compared with the <tt>pushLevel</tt>. If the given level is
+     * greater than or equal to the <tt>pushLevel</tt> then <tt>push</tt>
+     * is called to write all buffered records to the target output
+     * <tt>Handler</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        int ix = (start+count)%buffer.length;
+        buffer[ix] = record;
+        if (count < buffer.length) {
+            count++;
+        } else {
+            start++;
+            start %= buffer.length;
+        }
+        if (record.getLevel().intValue() >= pushLevel.intValue()) {
+            push();
+        }
+    }
+
+    /**
+     * Push any buffered output to the target <tt>Handler</tt>.
+     * <p>
+     * The buffer is then cleared.
+     */
+    public synchronized void push() {
+        for (int i = 0; i < count; i++) {
+            int ix = (start+i)%buffer.length;
+            LogRecord record = buffer[ix];
+            target.publish(record);
+        }
+        // Empty the buffer.
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Causes a flush on the target <tt>Handler</tt>.
+     * <p>
+     * Note that the current contents of the <tt>MemoryHandler</tt>
+     * buffer are <b>not</b> written out.  That requires a "push".
+     */
+    @Override
+    public void flush() {
+        target.flush();
+    }
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * This will also close the target <tt>Handler</tt>.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public void close() throws SecurityException {
+        target.close();
+        setLevel(Level.OFF);
+    }
+
+    /**
+     * Set the <tt>pushLevel</tt>.  After a <tt>LogRecord</tt> is copied
+     * into our internal buffer, if its level is greater than or equal to
+     * the <tt>pushLevel</tt>, then <tt>push</tt> will be called.
+     *
+     * @param newLevel the new value of the <tt>pushLevel</tt>
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setPushLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        pushLevel = newLevel;
+    }
+
+    /**
+     * Get the <tt>pushLevel</tt>.
+     *
+     * @return the value of the <tt>pushLevel</tt>
+     */
+    public Level getPushLevel() {
+        return pushLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given
+     * <tt>LogRecord</tt> into its internal buffer.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  However it does <b>not</b>
+     * check whether the <tt>LogRecord</tt> would result in a "push" of the
+     * buffer contents. It will return false if the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        return super.isLoggable(record);
+    }
+}
diff --git a/android-35/java/util/logging/SimpleFormatter.java b/android-35/java/util/logging/SimpleFormatter.java
new file mode 100644
index 0000000..12412f1
--- /dev/null
+++ b/android-35/java/util/logging/SimpleFormatter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.text.*;
+import java.util.Date;
+import sun.util.logging.LoggingSupport;
+
+/**
+ * Print a brief summary of the {@code LogRecord} in a human readable
+ * format.  The summary will typically be 1 or 2 lines.
+ *
+ * <p>
+ * <a name="formatting">
+ * <b>Configuration:</b></a>
+ * The {@code SimpleFormatter} is initialized with the
+ * <a href="../Formatter.html#syntax">format string</a>
+ * specified in the {@code java.util.logging.SimpleFormatter.format}
+ * property to {@linkplain #format format} the log messages.
+ * This property can be defined
+ * in the {@linkplain LogManager#getProperty logging properties}
+ * configuration file
+ * or as a system property.  If this property is set in both
+ * the logging properties and system properties,
+ * the format string specified in the system property will be used.
+ * If this property is not defined or the given format string
+ * is {@linkplain java.util.IllegalFormatException illegal},
+ * the default format is implementation-specific.
+ *
+ * @since 1.4
+ * @see java.util.Formatter
+ */
+
+public class SimpleFormatter extends Formatter {
+
+    // format string for printing the log record
+    private static final String format = LoggingSupport.getSimpleFormat();
+    private final Date dat = new Date();
+
+    /**
+     * Format the given LogRecord.
+     * <p>
+     * The formatting can be customized by specifying the
+     * <a href="../Formatter.html#syntax">format string</a>
+     * in the <a href="#formatting">
+     * {@code java.util.logging.SimpleFormatter.format}</a> property.
+     * The given {@code LogRecord} will be formatted as if by calling:
+     * <pre>
+     *    {@link String#format String.format}(format, date, source, logger, level, message, thrown);
+     * </pre>
+     * where the arguments are:<br>
+     * <ol>
+     * <li>{@code format} - the {@link java.util.Formatter
+     *     java.util.Formatter} format string specified in the
+     *     {@code java.util.logging.SimpleFormatter.format} property
+     *     or the default format.</li>
+     * <li>{@code date} - a {@link Date} object representing
+     *     {@linkplain LogRecord#getMillis event time} of the log record.</li>
+     * <li>{@code source} - a string representing the caller, if available;
+     *     otherwise, the logger's name.</li>
+     * <li>{@code logger} - the logger's name.</li>
+     * <li>{@code level} - the {@linkplain Level#getLocalizedName
+     *     log level}.</li>
+     * <li>{@code message} - the formatted log message
+     *     returned from the {@link Formatter#formatMessage(LogRecord)}
+     *     method.  It uses {@link java.text.MessageFormat java.text}
+     *     formatting and does not use the {@code java.util.Formatter
+     *     format} argument.</li>
+     * <li>{@code thrown} - a string representing
+     *     the {@linkplain LogRecord#getThrown throwable}
+     *     associated with the log record and its backtrace
+     *     beginning with a newline character, if any;
+     *     otherwise, an empty string.</li>
+     * </ol>
+     *
+     * <p>Some example formats:<br>
+     * <ul>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"}
+     *     <p>This prints 1 line with the log level ({@code 4$}),
+     *     the log message ({@code 5$}) and the timestamp ({@code 1$}) in
+     *     a square bracket.
+     *     <pre>
+     *     WARNING: warning message [Tue Mar 22 13:11:31 PDT 2011]
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tc %2$s%n%4$s: %5$s%6$s%n"}
+     *     <p>This prints 2 lines where the first line includes
+     *     the timestamp ({@code 1$}) and the source ({@code 2$});
+     *     the second line includes the log level ({@code 4$}) and
+     *     the log message ({@code 5$}) followed with the throwable
+     *     and its backtrace ({@code 6$}), if any:
+     *     <pre>
+     *     Tue Mar 22 13:11:31 PDT 2011 MyClass fatal
+     *     SEVERE: several message with an exception
+     *     java.lang.IllegalArgumentException: invalid argument
+     *             at MyClass.mash(MyClass.java:9)
+     *             at MyClass.crunch(MyClass.java:6)
+     *             at MyClass.main(MyClass.java:3)
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%n"}
+     *      <p>This prints 2 lines similar to the example above
+     *         with a different date/time formatting and does not print
+     *         the throwable and its backtrace:
+     *     <pre>
+     *     Mar 22, 2011 1:11:31 PM MyClass fatal
+     *     SEVERE: several message with an exception
+     *     </pre></li>
+     * </ul>
+     * <p>This method can also be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public synchronized String format(LogRecord record) {
+        dat.setTime(record.getMillis());
+        String source;
+        if (record.getSourceClassName() != null) {
+            source = record.getSourceClassName();
+            if (record.getSourceMethodName() != null) {
+               source += " " + record.getSourceMethodName();
+            }
+        } else {
+            source = record.getLoggerName();
+        }
+        String message = formatMessage(record);
+        String throwable = "";
+        if (record.getThrown() != null) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            pw.println();
+            record.getThrown().printStackTrace(pw);
+            pw.close();
+            throwable = sw.toString();
+        }
+        return String.format(format,
+                             dat,
+                             source,
+                             record.getLoggerName(),
+                             record.getLevel().getLocalizedLevelName(),
+                             message,
+                             throwable);
+    }
+}
diff --git a/android-35/java/util/logging/SocketHandler.java b/android-35/java/util/logging/SocketHandler.java
new file mode 100644
index 0000000..2561e90
--- /dev/null
+++ b/android-35/java/util/logging/SocketHandler.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.net.*;
+import libcore.net.NetworkSecurityPolicy;
+
+/**
+ * Simple network logging <tt>Handler</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a network stream connection.  By default
+ * the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>SocketHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.host
+ *        specifies the target host name to connect to (no default). </li>
+ * <li>   &lt;handler-name&gt;.port
+ *        specifies the target TCP port to use (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code SocketHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.SocketHandler.level=INFO </li>
+ * <li>   java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * The output IO stream is buffered, but is flushed after each
+ * <tt>LogRecord</tt> is written.
+ *
+ * @since 1.4
+ */
+
+public class SocketHandler extends StreamHandler {
+    private Socket sock;
+    private String host;
+    private int port;
+
+    // Private method to configure a SocketHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+        port = manager.getIntProperty(cname + ".port", 0);
+        host = manager.getStringProperty(cname + ".host", null);
+    }
+
+
+    /**
+     * Create a <tt>SocketHandler</tt>, using only <tt>LogManager</tt> properties
+     * (or their defaults).
+     * @throws IllegalArgumentException if the host or port are invalid or
+     *          are not specified as LogManager properties.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler() throws IOException {
+        // We are going to use the logging defaults.
+        sealed = false;
+        configure();
+
+        try {
+            connect();
+        } catch (IOException ix) {
+            System.err.println("SocketHandler: connect failed to " + host + ":" + port);
+            throw ix;
+        }
+        sealed = true;
+    }
+
+    /**
+     * Construct a <tt>SocketHandler</tt> using a specified host and port.
+     *
+     * The <tt>SocketHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given target host
+     * and port arguments are used. If the host argument is empty, but not
+     * null String then the localhost is used.
+     *
+     * @param host target host.
+     * @param port target port.
+     *
+     * @throws IllegalArgumentException if the host or port are invalid.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler(String host, int port) throws IOException {
+        sealed = false;
+        configure();
+        sealed = true;
+        this.port = port;
+        this.host = host;
+        connect();
+    }
+
+    private void connect() throws IOException {
+        // Check the arguments are valid.
+        if (port == 0) {
+            throw new IllegalArgumentException("Bad port: " + port);
+        }
+        if (host == null) {
+            throw new IllegalArgumentException("Null host name: " + host);
+        }
+
+        // Android-added: Enforce cleartext policy.
+        if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()) {
+            throw new IOException("Cleartext traffic not permitted");
+        }
+
+        // Try to open a new socket.
+        sock = new Socket(host, port);
+        OutputStream out = sock.getOutputStream();
+        BufferedOutputStream bout = new BufferedOutputStream(out);
+        setOutputStream(bout);
+    }
+
+    /**
+     * Close this output stream.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        if (sock != null) {
+            try {
+                sock.close();
+            } catch (IOException ix) {
+                // drop through.
+            }
+        }
+        sock = null;
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+    }
+}
diff --git a/android-35/java/util/logging/StreamHandler.java b/android-35/java/util/logging/StreamHandler.java
new file mode 100644
index 0000000..3b5a276
--- /dev/null
+++ b/android-35/java/util/logging/StreamHandler.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+
+/**
+ * Stream based logging <tt>Handler</tt>.
+ * <p>
+ * This is primarily intended as a base class or support class to
+ * be used in implementing other logging <tt>Handlers</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a given <tt>java.io.OutputStream</tt>.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>StreamHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *         (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code StreamHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.StreamHandler.level=INFO </li>
+ * <li>   java.util.logging.StreamHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class StreamHandler extends Handler {
+    private OutputStream output;
+    private boolean doneHeader;
+    private volatile Writer writer;
+
+    // Private method to configure a StreamHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt>, with no current output stream.
+     */
+    public StreamHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt> with a given <tt>Formatter</tt>
+     * and output stream.
+     * <p>
+     * @param out         the target output stream
+     * @param formatter   Formatter to be used to format output
+     */
+    public StreamHandler(OutputStream out, Formatter formatter) {
+        sealed = false;
+        configure();
+        setFormatter(formatter);
+        setOutputStream(out);
+        sealed = true;
+    }
+
+    /**
+     * Change the output stream.
+     * <P>
+     * If there is a current output stream then the <tt>Formatter</tt>'s
+     * tail string is written and the stream is flushed and closed.
+     * Then the output stream is replaced with the new output stream.
+     *
+     * @param out   New output stream.  May not be null.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
+        if (out == null) {
+            throw new NullPointerException();
+        }
+        flushAndClose();
+        output = out;
+        doneHeader = false;
+        String encoding = getEncoding();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            try {
+                writer = new OutputStreamWriter(output, encoding);
+            } catch (UnsupportedEncodingException ex) {
+                // This shouldn't happen.  The setEncoding method
+                // should have validated that the encoding is OK.
+                throw new Error("Unexpected exception " + ex);
+            }
+        }
+    }
+
+    /**
+     * Set (or change) the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    @Override
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        super.setEncoding(encoding);
+        if (output == null) {
+            return;
+        }
+        // Replace the current writer with a writer for the new encoding.
+        flush();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            writer = new OutputStreamWriter(output, encoding);
+        }
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     * <p>
+     * The <tt>StreamHandler</tt> first checks if there is an <tt>OutputStream</tt>
+     * and if the given <tt>LogRecord</tt> has at least the required log level.
+     * If not it silently returns.  If so, it calls any associated
+     * <tt>Filter</tt> to check if the record should be published.  If so,
+     * it calls its <tt>Formatter</tt> to format the record and then writes
+     * the result to the current output stream.
+     * <p>
+     * If this is the first <tt>LogRecord</tt> to be written to a given
+     * <tt>OutputStream</tt>, the <tt>Formatter</tt>'s "head" string is
+     * written to the stream before the <tt>LogRecord</tt> is written.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        String msg;
+        try {
+            msg = getFormatter().format(record);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.FORMAT_FAILURE);
+            return;
+        }
+
+        try {
+            if (!doneHeader) {
+                writer.write(getFormatter().getHead(this));
+                doneHeader = true;
+            }
+            writer.write(msg);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.WRITE_FAILURE);
+        }
+    }
+
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  It will also return false if
+     * no output stream has been assigned yet or the LogRecord is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        if (writer == null || record == null) {
+            return false;
+        }
+        return super.isLoggable(record);
+    }
+
+    /**
+     * Flush any buffered messages.
+     */
+    @Override
+    public synchronized void flush() {
+        if (writer != null) {
+            try {
+                writer.flush();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.FLUSH_FAILURE);
+            }
+        }
+    }
+
+    private synchronized void flushAndClose() throws SecurityException {
+        checkPermission();
+        if (writer != null) {
+            try {
+                if (!doneHeader) {
+                    writer.write(getFormatter().getHead(this));
+                    doneHeader = true;
+                }
+                writer.write(getFormatter().getTail(this));
+                writer.flush();
+                writer.close();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.CLOSE_FAILURE);
+            }
+            writer = null;
+            output = null;
+        }
+    }
+
+    /**
+     * Close the current output stream.
+     * <p>
+     * The <tt>Formatter</tt>'s "tail" string is written to the stream before it
+     * is closed.  In addition, if the <tt>Formatter</tt>'s "head" string has not
+     * yet been written to the stream, it will be written before the
+     * "tail" string.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        flushAndClose();
+    }
+}
diff --git a/android-35/java/util/logging/XMLFormatter.java b/android-35/java/util/logging/XMLFormatter.java
new file mode 100644
index 0000000..ab95f58
--- /dev/null
+++ b/android-35/java/util/logging/XMLFormatter.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * Format a LogRecord into a standard XML format.
+ * <p>
+ * The DTD specification is provided as Appendix A to the
+ * Java Logging APIs specification.
+ * <p>
+ * The XMLFormatter can be used with arbitrary character encodings,
+ * but it is recommended that it normally be used with UTF-8.  The
+ * character encoding can be set on the output Handler.
+ *
+ * @since 1.4
+ */
+
+public class XMLFormatter extends Formatter {
+    private LogManager manager = LogManager.getLogManager();
+
+    // Append a two digit number.
+    private void a2(StringBuilder sb, int x) {
+        if (x < 10) {
+            sb.append('0');
+        }
+        sb.append(x);
+    }
+
+    // Append the time and date in ISO 8601 format
+    private void appendISO8601(StringBuilder sb, long millis) {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTimeInMillis(millis);
+        sb.append(cal.get(Calendar.YEAR));
+        sb.append('-');
+        a2(sb, cal.get(Calendar.MONTH) + 1);
+        sb.append('-');
+        a2(sb, cal.get(Calendar.DAY_OF_MONTH));
+        sb.append('T');
+        a2(sb, cal.get(Calendar.HOUR_OF_DAY));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.MINUTE));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.SECOND));
+    }
+
+    // Append to the given StringBuilder an escaped version of the
+    // given text string where XML special characters have been escaped.
+    // For a null string we append "<null>"
+    private void escape(StringBuilder sb, String text) {
+        if (text == null) {
+            text = "<null>";
+        }
+        for (int i = 0; i < text.length(); i++) {
+            char ch = text.charAt(i);
+            if (ch == '<') {
+                sb.append("&lt;");
+            } else if (ch == '>') {
+                sb.append("&gt;");
+            } else if (ch == '&') {
+                sb.append("&amp;");
+            } else {
+                sb.append(ch);
+            }
+        }
+    }
+
+    /**
+     * Format the given message to XML.
+     * <p>
+     * This method can be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public String format(LogRecord record) {
+        StringBuilder sb = new StringBuilder(500);
+        sb.append("<record>\n");
+
+        sb.append("  <date>");
+        appendISO8601(sb, record.getMillis());
+        sb.append("</date>\n");
+
+        sb.append("  <millis>");
+        sb.append(record.getMillis());
+        sb.append("</millis>\n");
+
+        sb.append("  <sequence>");
+        sb.append(record.getSequenceNumber());
+        sb.append("</sequence>\n");
+
+        String name = record.getLoggerName();
+        if (name != null) {
+            sb.append("  <logger>");
+            escape(sb, name);
+            sb.append("</logger>\n");
+        }
+
+        sb.append("  <level>");
+        escape(sb, record.getLevel().toString());
+        sb.append("</level>\n");
+
+        if (record.getSourceClassName() != null) {
+            sb.append("  <class>");
+            escape(sb, record.getSourceClassName());
+            sb.append("</class>\n");
+        }
+
+        if (record.getSourceMethodName() != null) {
+            sb.append("  <method>");
+            escape(sb, record.getSourceMethodName());
+            sb.append("</method>\n");
+        }
+
+        sb.append("  <thread>");
+        sb.append(record.getThreadID());
+        sb.append("</thread>\n");
+
+        if (record.getMessage() != null) {
+            // Format the message string and its accompanying parameters.
+            String message = formatMessage(record);
+            sb.append("  <message>");
+            escape(sb, message);
+            sb.append("</message>");
+            sb.append("\n");
+        // Android-added: Include empty <message/> tag. http://b/25861348#comment17
+        } else {
+            sb.append("<message/>");
+            sb.append("\n");
+        }
+
+        // If the message is being localized, output the key, resource
+        // bundle name, and params.
+        ResourceBundle bundle = record.getResourceBundle();
+        try {
+            if (bundle != null && bundle.getString(record.getMessage()) != null) {
+                sb.append("  <key>");
+                escape(sb, record.getMessage());
+                sb.append("</key>\n");
+                sb.append("  <catalog>");
+                escape(sb, record.getResourceBundleName());
+                sb.append("</catalog>\n");
+            }
+        } catch (Exception ex) {
+            // The message is not in the catalog.  Drop through.
+        }
+
+        Object parameters[] = record.getParameters();
+        //  Check to see if the parameter was not a messagetext format
+        //  or was not null or empty
+        if ( parameters != null && parameters.length != 0
+                && record.getMessage().indexOf("{") == -1 ) {
+            for (int i = 0; i < parameters.length; i++) {
+                sb.append("  <param>");
+                try {
+                    escape(sb, parameters[i].toString());
+                } catch (Exception ex) {
+                    sb.append("???");
+                }
+                sb.append("</param>\n");
+            }
+        }
+
+        if (record.getThrown() != null) {
+            // Report on the state of the throwable.
+            Throwable th = record.getThrown();
+            sb.append("  <exception>\n");
+            sb.append("    <message>");
+            escape(sb, th.toString());
+            sb.append("</message>\n");
+            StackTraceElement trace[] = th.getStackTrace();
+            for (int i = 0; i < trace.length; i++) {
+                StackTraceElement frame = trace[i];
+                sb.append("    <frame>\n");
+                sb.append("      <class>");
+                escape(sb, frame.getClassName());
+                sb.append("</class>\n");
+                sb.append("      <method>");
+                escape(sb, frame.getMethodName());
+                sb.append("</method>\n");
+                // Check for a line number.
+                if (frame.getLineNumber() >= 0) {
+                    sb.append("      <line>");
+                    sb.append(frame.getLineNumber());
+                    sb.append("</line>\n");
+                }
+                sb.append("    </frame>\n");
+            }
+            sb.append("  </exception>\n");
+        }
+
+        sb.append("</record>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the header string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getHead(Handler h) {
+        StringBuilder sb = new StringBuilder();
+        String encoding;
+        sb.append("<?xml version=\"1.0\"");
+
+        if (h != null) {
+            encoding = h.getEncoding();
+        } else {
+            encoding = null;
+        }
+
+        if (encoding == null) {
+            // Figure out the default encoding.
+            encoding = java.nio.charset.Charset.defaultCharset().name();
+        }
+        // Try to map the encoding name to a canonical name.
+        try {
+            Charset cs = Charset.forName(encoding);
+            encoding = cs.name();
+        } catch (Exception ex) {
+            // We hit problems finding a canonical name.
+            // Just use the raw encoding name.
+        }
+
+        sb.append(" encoding=\"");
+        sb.append(encoding);
+        sb.append("\"");
+        sb.append(" standalone=\"no\"?>\n");
+        sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
+        sb.append("<log>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the tail string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getTail(Handler h) {
+        return "</log>\n";
+    }
+}
diff --git a/android-35/java/util/logging/package-info.java b/android-35/java/util/logging/package-info.java
new file mode 100644
index 0000000..d398fd3
--- /dev/null
+++ b/android-35/java/util/logging/package-info.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides the classes and interfaces of
+ * the Java 2 platform's core logging facilities.
+ * The central goal of the logging APIs is to support maintaining and servicing
+ * software at customer sites.
+ *
+ * <P>
+ * There are four main target uses of the logs:
+ * </P>
+ *
+ * <OL>
+ *    <LI> <I>Problem diagnosis by end users and system administrators</I>.
+ *           This consists of simple logging of common problems that can be fixed
+ *           or tracked locally, such as running out of resources, security failures,
+ *           and simple configuration errors.
+ *
+ *    <LI> <I>Problem diagnosis by field service engineers</I>. The logging information
+ *            used by field service engineers may be considerably more complex and
+ *            verbose than that required by system administrators.  Typically such information
+ *            will require extra logging within particular subsystems.
+ *
+ *    <LI> <I>Problem diagnosis by the development organization</I>.
+ *          When a problem occurs in the field, it may be necessary to return the captured logging
+ *          information to the original development team for diagnosis. This logging
+ *          information may be extremely detailed and fairly inscrutable. Such information might include
+ *          detailed tracing on the internal execution of particular subsystems.
+ *
+ *    <LI> <I>Problem diagnosis by developers</I>. The Logging APIs may also be
+ *            used to help debug an application under development. This may
+ *            include logging information generated by the target application
+ *            as well as logging information generated by lower-level libraries.
+ *            Note however that while this use is perfectly reasonable,
+ *            the logging APIs are not intended to replace the normal debugging
+ *            and profiling tools that may already exist in the development environment.
+ * </OL>
+ *
+ * <p>
+ * The key elements of this package include:
+ * <UL>
+ *    <LI> <I>Logger</I>: The main entity on which applications make
+ *                 logging calls. A Logger object is used to log messages
+ *                 for a specific system or application
+ *                 component.
+ *    <LI> <I>LogRecord</I>: Used to pass logging requests between the logging
+ *                    framework and individual log handlers.
+ *    <LI> <I>Handler</I>: Exports LogRecord objects to a variety of destinations
+ *                  including memory, output streams, consoles, files, and sockets.
+ *                  A variety of Handler subclasses exist for this purpose. Additional Handlers
+ *                  may be developed by third parties and delivered on top of the core platform.
+ *    <LI> <I>Level</I>: Defines a set of standard logging levels that can be used
+ *                       to control logging output. Programs can be configured to output logging
+ *                       for some levels while ignoring output for others.
+ *    <LI> <I>Filter</I>: Provides fine-grained control over what gets logged,
+ *                        beyond the control provided by log levels. The logging APIs support a general-purpose
+ *                        filter mechanism that allows application code to attach arbitrary filters to
+ *                        control logging output.
+ *
+ *    <LI> <I>Formatter</I>: Provides support for formatting LogRecord objects. This
+ *                           package includes two formatters, SimpleFormatter and
+ *                           XMLFormatter, for formatting log records in plain text
+ *                           or XML respectively. As with Handlers, additional Formatters
+ *                           may be developed by third parties.
+ * </UL>
+ * <P>
+ * The Logging APIs offer both static and dynamic configuration control.
+ * Static control enables field service staff to set up a particular configuration and then re-launch the
+ * application with the new logging settings. Dynamic control allows for updates to the
+ * logging configuration within a currently running program. The APIs also allow for logging to be
+ * enabled or disabled for different functional areas of the system. For example,
+ * a field service engineer might be interested in tracing all AWT events, but might have no interest in
+ * socket events or memory management.
+ * </P>
+ *
+ * <h2>Null Pointers</h2>
+ * <p>
+ * In general, unless otherwise noted in the javadoc, methods and
+ * constructors will throw NullPointerException if passed a null argument.
+ * The one broad exception to this rule is that the logging convenience
+ * methods in the Logger class (the config, entering, exiting, fine, finer, finest,
+ * log, logp, logrb, severe, throwing, and warning methods)
+ * will accept null values
+ * for all arguments except for the initial Level argument (if any).
+ *
+ * <H2>Related Documentation</H2>
+ * <P>
+ * For an overview of control flow,
+ * please refer to the
+ * <a href="https://docs.oracle.com/pls/topic/lookup?ctx=javase17&id=logging_overview">Java Logging Overview</a>
+ * </P>
+ *
+ * @since 1.4
+ */
+package java.util.logging;
diff --git a/android-35/java/util/package-info.java b/android-35/java/util/package-info.java
new file mode 100644
index 0000000..814aa11
--- /dev/null
+++ b/android-35/java/util/package-info.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Contains the collections framework, some internationalization support classes,
+ * a service loader, properties, random number generation, string parsing
+ * and scanning classes, base64 encoding and decoding, a bit array, and
+ * several miscellaneous utility classes. This package also contains
+ * legacy collection classes and legacy date and time classes.
+ *
+ * <h2><a id="CollectionsFramework"></a>"Java Collections Framework"</h2>
+ * <p>For an overview, API outline, and design rationale, please see:
+ * <ul>
+ *   <li><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/doc-files/coll-index.html">
+ *          <b>Collections Framework Documentation</b></a>
+ * </ul>
+ *
+ * <p>For a tutorial and programming guide with examples of use
+ * of the collections framework, please see:
+ * <ul>
+ *   <li><a href="http://docs.oracle.com/javase/tutorial/collections/index.html">
+ *          <b>Collections Framework Tutorial</b></a>
+ * </ul>
+ *
+ * @since 1.0
+ */
+package java.util;
diff --git a/android-35/java/util/prefs/AbstractPreferences.java b/android-35/java/util/prefs/AbstractPreferences.java
new file mode 100644
index 0000000..71616ee
--- /dev/null
+++ b/android-35/java/util/prefs/AbstractPreferences.java
@@ -0,0 +1,1669 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * This class provides a skeletal implementation of the {@link Preferences}
+ * class, greatly easing the task of implementing it.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.  The {@link Preferences} documentation
+ * should suffice.</strong>
+ *
+ * <p>Implementors must override the nine abstract service-provider interface
+ * (SPI) methods: {@link #getSpi(String)}, {@link #putSpi(String,String)},
+ * {@link #removeSpi(String)}, {@link #childSpi(String)}, {@link
+ * #removeNodeSpi()}, {@link #keysSpi()}, {@link #childrenNamesSpi()}, {@link
+ * #syncSpi()} and {@link #flushSpi()}.  All of the concrete methods specify
+ * precisely how they are implemented atop these SPI methods.  The implementor
+ * may, at his discretion, override one or more of the concrete methods if the
+ * default implementation is unsatisfactory for any reason, such as
+ * performance.
+ *
+ * <p>The SPI methods fall into three groups concerning exception
+ * behavior. The <tt>getSpi</tt> method should never throw exceptions, but it
+ * doesn't really matter, as any exception thrown by this method will be
+ * intercepted by {@link #get(String,String)}, which will return the specified
+ * default value to the caller.  The <tt>removeNodeSpi, keysSpi,
+ * childrenNamesSpi, syncSpi</tt> and <tt>flushSpi</tt> methods are specified
+ * to throw {@link BackingStoreException}, and the implementation is required
+ * to throw this checked exception if it is unable to perform the operation.
+ * The exception propagates outward, causing the corresponding API method
+ * to fail.
+ *
+ * <p>The remaining SPI methods {@link #putSpi(String,String)}, {@link
+ * #removeSpi(String)} and {@link #childSpi(String)} have more complicated
+ * exception behavior.  They are not specified to throw
+ * <tt>BackingStoreException</tt>, as they can generally obey their contracts
+ * even if the backing store is unavailable.  This is true because they return
+ * no information and their effects are not required to become permanent until
+ * a subsequent call to {@link Preferences#flush()} or
+ * {@link Preferences#sync()}. Generally speaking, these SPI methods should not
+ * throw exceptions.  In some implementations, there may be circumstances
+ * under which these calls cannot even enqueue the requested operation for
+ * later processing.  Even under these circumstances it is generally better to
+ * simply ignore the invocation and return, rather than throwing an
+ * exception.  Under these circumstances, however, all subsequent invocations
+ * of <tt>flush()</tt> and <tt>sync</tt> should return <tt>false</tt>, as
+ * returning <tt>true</tt> would imply that all previous operations had
+ * successfully been made permanent.
+ *
+ * <p>There is one circumstance under which <tt>putSpi, removeSpi and
+ * childSpi</tt> <i>should</i> throw an exception: if the caller lacks
+ * sufficient privileges on the underlying operating system to perform the
+ * requested operation.  This will, for instance, occur on most systems
+ * if a non-privileged user attempts to modify system preferences.
+ * (The required privileges will vary from implementation to
+ * implementation.  On some implementations, they are the right to modify the
+ * contents of some directory in the file system; on others they are the right
+ * to modify contents of some key in a registry.)  Under any of these
+ * circumstances, it would generally be undesirable to let the program
+ * continue executing as if these operations would become permanent at a later
+ * time.  While implementations are not required to throw an exception under
+ * these circumstances, they are encouraged to do so.  A {@link
+ * SecurityException} would be appropriate.
+ *
+ * <p>Most of the SPI methods require the implementation to read or write
+ * information at a preferences node.  The implementor should beware of the
+ * fact that another VM may have concurrently deleted this node from the
+ * backing store.  It is the implementation's responsibility to recreate the
+ * node if it has been deleted.
+ *
+ * <p>Implementation note: In Sun's default <tt>Preferences</tt>
+ * implementations, the user's identity is inherited from the underlying
+ * operating system and does not change for the lifetime of the virtual
+ * machine.  It is recognized that server-side <tt>Preferences</tt>
+ * implementations may have the user identity change from request to request,
+ * implicitly passed to <tt>Preferences</tt> methods via the use of a
+ * static {@link ThreadLocal} instance.  Authors of such implementations are
+ * <i>strongly</i> encouraged to determine the user at the time preferences
+ * are accessed (for example by the {@link #get(String,String)} or {@link
+ * #put(String,String)} method) rather than permanently associating a user
+ * with each <tt>Preferences</tt> instance.  The latter behavior conflicts
+ * with normal <tt>Preferences</tt> usage and would lead to great confusion.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public abstract class AbstractPreferences extends Preferences {
+    /**
+     * Our name relative to parent.
+     */
+    private final String name;
+
+    /**
+     * Our absolute path name.
+     */
+    private final String absolutePath;
+
+    /**
+     * Our parent node.
+     */
+    final AbstractPreferences parent;
+
+    /**
+     * Our root node.
+     */
+    private final AbstractPreferences root; // Relative to this node
+
+    /**
+     * This field should be <tt>true</tt> if this node did not exist in the
+     * backing store prior to the creation of this object.  The field
+     * is initialized to false, but may be set to true by a subclass
+     * constructor (and should not be modified thereafter).  This field
+     * indicates whether a node change event should be fired when
+     * creation is complete.
+     */
+    protected boolean newNode = false;
+
+    /**
+     * All known unremoved children of this node.  (This "cache" is consulted
+     * prior to calling childSpi() or getChild().
+     */
+    private Map<String, AbstractPreferences> kidCache = new HashMap<>();
+
+    /**
+     * This field is used to keep track of whether or not this node has
+     * been removed.  Once it's set to true, it will never be reset to false.
+     */
+    private boolean removed = false;
+
+    /**
+     * Registered preference change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // It's not clear if this change provides overall benefit; it might be
+    // reverted in future. Discussion: http://b/111195881
+    // private PreferenceChangeListener[] prefListeners =
+    //     new PreferenceChangeListener[0];
+    private final ArrayList<PreferenceChangeListener> prefListeners = new ArrayList<>();
+
+    /**
+     * Registered node change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // private NodeChangeListener[] nodeListeners = new NodeChangeListener[0];
+    private final ArrayList<NodeChangeListener> nodeListeners = new ArrayList<>();
+
+    /**
+     * An object whose monitor is used to lock this node.  This object
+     * is used in preference to the node itself to reduce the likelihood of
+     * intentional or unintentional denial of service due to a locked node.
+     * To avoid deadlock, a node is <i>never</i> locked by a thread that
+     * holds a lock on a descendant of that node.
+     */
+    protected final Object lock = new Object();
+
+    /**
+     * Creates a preference node with the specified parent and the specified
+     * name relative to its parent.
+     *
+     * @param parent the parent of this preference node, or null if this
+     *               is the root.
+     * @param name the name of this preference node, relative to its parent,
+     *             or <tt>""</tt> if this is the root.
+     * @throws IllegalArgumentException if <tt>name</tt> contains a slash
+     *          (<tt>'/'</tt>),  or <tt>parent</tt> is <tt>null</tt> and
+     *          name isn't <tt>""</tt>.
+     */
+    protected AbstractPreferences(AbstractPreferences parent, String name) {
+        if (parent==null) {
+            if (!name.equals(""))
+                throw new IllegalArgumentException("Root name '"+name+
+                                                   "' must be \"\"");
+            this.absolutePath = "/";
+            root = this;
+        } else {
+            if (name.indexOf('/') != -1)
+                throw new IllegalArgumentException("Name '" + name +
+                                                 "' contains '/'");
+            if (name.equals(""))
+              throw new IllegalArgumentException("Illegal name: empty string");
+
+            root = parent.root;
+            absolutePath = (parent==root ? "/" + name
+                                         : parent.absolutePath() + "/" + name);
+        }
+        this.name = name;
+        this.parent = parent;
+    }
+
+    /**
+     * Implements the <tt>put</tt> method as per the specification in
+     * {@link Preferences#put(String,String)}.
+     *
+     * <p>This implementation checks that the key and value are legal,
+     * obtains this preference node's lock, checks that the node
+     * has not been removed, invokes {@link #putSpi(String,String)}, and if
+     * there are any preference change listeners, enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void put(String key, String value) {
+        if (key==null || value==null)
+            throw new NullPointerException();
+        if (key.length() > MAX_KEY_LENGTH)
+            throw new IllegalArgumentException("Key too long: "+key);
+        if (value.length() > MAX_VALUE_LENGTH)
+            throw new IllegalArgumentException("Value too long: "+value);
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            putSpi(key, value);
+            enqueuePreferenceChangeEvent(key, value);
+        }
+    }
+
+    /**
+     * Implements the <tt>get</tt> method as per the specification in
+     * {@link Preferences#get(String,String)}.
+     *
+     * <p>This implementation first checks to see if <tt>key</tt> is
+     * <tt>null</tt> throwing a <tt>NullPointerException</tt> if this is
+     * the case.  Then it obtains this preference node's lock,
+     * checks that the node has not been removed, invokes {@link
+     * #getSpi(String)}, and returns the result, unless the <tt>getSpi</tt>
+     * invocation returns <tt>null</tt> or throws an exception, in which case
+     * this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if key is <tt>null</tt>.  (A
+     *         <tt>null</tt> default <i>is</i> permitted.)
+     */
+    public String get(String key, String def) {
+        if (key==null)
+            throw new NullPointerException("Null key");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            String result = null;
+            try {
+                result = getSpi(key);
+            } catch (Exception e) {
+                // Ignoring exception causes default to be returned
+            }
+            return (result==null ? def : result);
+        }
+    }
+
+    /**
+     * Implements the <tt>remove(String)</tt> method as per the specification
+     * in {@link Preferences#remove(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * checks that the node has not been removed, invokes
+     * {@link #removeSpi(String)} and if there are any preference
+     * change listeners, enqueues a notification event for processing by the
+     * event dispatch thread.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException {@inheritDoc}.
+     */
+    public void remove(String key) {
+        Objects.requireNonNull(key, "Specified key cannot be null");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            removeSpi(key);
+            enqueuePreferenceChangeEvent(key, null);
+        }
+    }
+
+    /**
+     * Implements the <tt>clear</tt> method as per the specification in
+     * {@link Preferences#clear()}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * invokes {@link #keys()} to obtain an array of keys, and
+     * iterates over the array invoking {@link #remove(String)} on each key.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void clear() throws BackingStoreException {
+        synchronized(lock) {
+            String[] keys = keys();
+            for (int i=0; i<keys.length; i++)
+                remove(keys[i]);
+        }
+    }
+
+    /**
+     * Implements the <tt>putInt</tt> method as per the specification in
+     * {@link Preferences#putInt(String,int)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Integer#toString(int)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putInt(String key, int value) {
+        put(key, Integer.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getInt</tt> method as per the specification in
+     * {@link Preferences#getInt(String,int)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>int</tt> with
+     * {@link Integer#parseInt(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public int getInt(String key, int def) {
+        int result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putLong</tt> method as per the specification in
+     * {@link Preferences#putLong(String,long)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Long#toString(long)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putLong(String key, long value) {
+        put(key, Long.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getLong</tt> method as per the specification in
+     * {@link Preferences#getLong(String,long)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to a <tt>long</tt> with
+     * {@link Long#parseLong(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public long getLong(String key, long def) {
+        long result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putBoolean</tt> method as per the specification in
+     * {@link Preferences#putBoolean(String,boolean)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link String#valueOf(boolean)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putBoolean(String key, boolean value) {
+        put(key, String.valueOf(value));
+    }
+
+    /**
+     * Implements the <tt>getBoolean</tt> method as per the specification in
+     * {@link Preferences#getBoolean(String,boolean)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, it is compared with
+     * <tt>"true"</tt> using {@link String#equalsIgnoreCase(String)}.  If the
+     * comparison returns <tt>true</tt>, this invocation returns
+     * <tt>true</tt>.  Otherwise, the original return value is compared with
+     * <tt>"false"</tt>, again using {@link String#equalsIgnoreCase(String)}.
+     * If the comparison returns <tt>true</tt>, this invocation returns
+     * <tt>false</tt>.  Otherwise, this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public boolean getBoolean(String key, boolean def) {
+        boolean result = def;
+        String value = get(key, null);
+        if (value != null) {
+            if (value.equalsIgnoreCase("true"))
+                result = true;
+            else if (value.equalsIgnoreCase("false"))
+                result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putFloat</tt> method as per the specification in
+     * {@link Preferences#putFloat(String,float)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Float#toString(float)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putFloat(String key, float value) {
+        put(key, Float.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getFloat</tt> method as per the specification in
+     * {@link Preferences#getFloat(String,float)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>float</tt> with
+     * {@link Float#parseFloat(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public float getFloat(String key, float def) {
+        float result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Float.parseFloat(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putDouble</tt> method as per the specification in
+     * {@link Preferences#putDouble(String,double)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Double#toString(double)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putDouble(String key, double value) {
+        put(key, Double.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getDouble</tt> method as per the specification in
+     * {@link Preferences#getDouble(String,double)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>double</tt> with
+     * {@link Double#parseDouble(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public double getDouble(String key, double def) {
+        double result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Double.parseDouble(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putByteArray</tt> method as per the specification in
+     * {@link Preferences#putByteArray(String,byte[])}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putByteArray(String key, byte[] value) {
+        put(key, Base64.byteArrayToBase64(value));
+    }
+
+    /**
+     * Implements the <tt>getByteArray</tt> method as per the specification in
+     * {@link Preferences#getByteArray(String,byte[])}.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public byte[] getByteArray(String key, byte[] def) {
+        byte[] result = def;
+        String value = get(key, null);
+        try {
+            if (value != null)
+                result = Base64.base64ToByteArray(value);
+        }
+        catch (RuntimeException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>keys</tt> method as per the specification in
+     * {@link Preferences#keys()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and invokes {@link #keysSpi()}.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public String[] keys() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return keysSpi();
+        }
+    }
+
+    /**
+     * Implements the <tt>children</tt> method as per the specification in
+     * {@link Preferences#childrenNames()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed, constructs a <tt>TreeSet</tt> initialized
+     * to the names of children already cached (the children in this node's
+     * "child-cache"), invokes {@link #childrenNamesSpi()}, and adds all of the
+     * returned child-names into the set.  The elements of the tree set are
+     * dumped into a <tt>String</tt> array using the <tt>toArray</tt> method,
+     * and this array is returned.
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #cachedChildren()
+     */
+    public String[] childrenNames() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            Set<String> s = new TreeSet<>(kidCache.keySet());
+            for (String kid : childrenNamesSpi())
+                s.add(kid);
+            return s.toArray(EMPTY_STRING_ARRAY);
+        }
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Returns all known unremoved children of this node.
+     *
+     * @return all known unremoved children of this node.
+     */
+    protected final AbstractPreferences[] cachedChildren() {
+        return kidCache.values().toArray(EMPTY_ABSTRACT_PREFS_ARRAY);
+    }
+
+    private static final AbstractPreferences[] EMPTY_ABSTRACT_PREFS_ARRAY
+        = new AbstractPreferences[0];
+
+    /**
+     * Implements the <tt>parent</tt> method as per the specification in
+     * {@link Preferences#parent()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and returns the parent value that was
+     * passed to this node's constructor.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences parent() {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return parent;
+        }
+    }
+
+    /**
+     * Implements the <tt>node</tt> method as per the specification in
+     * {@link Preferences#node(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock and checks
+     * that the node has not been removed.  If <tt>path</tt> is <tt>""</tt>,
+     * this node is returned; if <tt>path</tt> is <tt>"/"</tt>, this node's
+     * root is returned.  If the first character in <tt>path</tt> is
+     * not <tt>'/'</tt>, the implementation breaks <tt>path</tt> into
+     * tokens and recursively traverses the path from this node to the
+     * named node, "consuming" a name and a slash from <tt>path</tt> at
+     * each step of the traversal.  At each step, the current node is locked
+     * and the node's child-cache is checked for the named node.  If it is
+     * not found, the name is checked to make sure its length does not
+     * exceed <tt>MAX_NAME_LENGTH</tt>.  Then the {@link #childSpi(String)}
+     * method is invoked, and the result stored in this node's child-cache.
+     * If the newly created <tt>Preferences</tt> object's {@link #newNode}
+     * field is <tt>true</tt> and there are any node change listeners,
+     * a notification event is enqueued for processing by the event dispatch
+     * thread.
+     *
+     * <p>When there are no more tokens, the last value found in the
+     * child-cache or returned by <tt>childSpi</tt> is returned by this
+     * method.  If during the traversal, two <tt>"/"</tt> tokens occur
+     * consecutively, or the final token is <tt>"/"</tt> (rather than a name),
+     * an appropriate <tt>IllegalArgumentException</tt> is thrown.
+     *
+     * <p> If the first character of <tt>path</tt> is <tt>'/'</tt>
+     * (indicating an absolute path name) this preference node's
+     * lock is dropped prior to breaking <tt>path</tt> into tokens, and
+     * this method recursively traverses the path starting from the root
+     * (rather than starting from this node).  The traversal is otherwise
+     * identical to the one described for relative path names.  Dropping
+     * the lock on this node prior to commencing the traversal at the root
+     * node is essential to avoid the possibility of deadlock, as per the
+     * {@link #lock locking invariant}.
+     *
+     * @param path the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences node(String path) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals(""))
+                return this;
+            if (path.equals("/"))
+                return root;
+            if (path.charAt(0) != '/')
+                return node(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.node(new StringTokenizer(path.substring(1), "/", true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private Preferences node(StringTokenizer path) {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null) {
+                if (token.length() > MAX_NAME_LENGTH)
+                    throw new IllegalArgumentException(
+                        "Node name " + token + " too long");
+                child = childSpi(token);
+                if (child.newNode)
+                    enqueueNodeAddedEvent(child);
+                kidCache.put(token, child);
+            }
+            if (!path.hasMoreTokens())
+                return child;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.node(path);
+        }
+    }
+
+    /**
+     * Implements the <tt>nodeExists</tt> method as per the specification in
+     * {@link Preferences#nodeExists(String)}.
+     *
+     * <p>This implementation is very similar to {@link #node(String)},
+     * except that {@link #getChild(String)} is used instead of {@link
+     * #childSpi(String)}.
+     *
+     * @param path the path name of the node whose existence is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathname</tt> is not the empty string (<tt>""</tt>).
+     */
+    public boolean nodeExists(String path)
+        throws BackingStoreException
+    {
+        synchronized(lock) {
+            if (path.equals(""))
+                return !removed;
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals("/"))
+                return true;
+            if (path.charAt(0) != '/')
+                return nodeExists(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.nodeExists(new StringTokenizer(path.substring(1), "/",
+                                                   true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private boolean nodeExists(StringTokenizer path)
+        throws BackingStoreException
+    {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null)
+                child = getChild(token);
+            if (child==null)
+                return false;
+            if (!path.hasMoreTokens())
+                return true;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.nodeExists(path);
+        }
+    }
+
+    /**
+
+     * Implements the <tt>removeNode()</tt> method as per the specification in
+     * {@link Preferences#removeNode()}.
+     *
+     * <p>This implementation checks to see that this node is the root; if so,
+     * it throws an appropriate exception.  Then, it locks this node's parent,
+     * and calls a recursive helper method that traverses the subtree rooted at
+     * this node.  The recursive method locks the node on which it was called,
+     * checks that it has not already been removed, and then ensures that all
+     * of its children are cached: The {@link #childrenNamesSpi()} method is
+     * invoked and each returned child name is checked for containment in the
+     * child-cache.  If a child is not already cached, the {@link
+     * #childSpi(String)} method is invoked to create a <tt>Preferences</tt>
+     * instance for it, and this instance is put into the child-cache.  Then
+     * the helper method calls itself recursively on each node contained in its
+     * child-cache.  Next, it invokes {@link #removeNodeSpi()}, marks itself
+     * as removed, and removes itself from its parent's child-cache.  Finally,
+     * if there are any node change listeners, it enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * <p>Note that the helper method is always invoked with all ancestors up
+     * to the "closest non-removed ancestor" locked.
+     *
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    public void removeNode() throws BackingStoreException {
+        if (this==root)
+            throw new UnsupportedOperationException("Can't remove the root!");
+        synchronized(parent.lock) {
+            removeNode2();
+            parent.kidCache.remove(name);
+        }
+    }
+
+    /*
+     * Called with locks on all nodes on path from parent of "removal root"
+     * to this (including the former but excluding the latter).
+     */
+    private void removeNode2() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node already removed.");
+
+            // Ensure that all children are cached
+            String[] kidNames = childrenNamesSpi();
+            for (int i=0; i<kidNames.length; i++)
+                if (!kidCache.containsKey(kidNames[i]))
+                    kidCache.put(kidNames[i], childSpi(kidNames[i]));
+
+            // Recursively remove all cached children
+            for (Iterator<AbstractPreferences> i = kidCache.values().iterator();
+                 i.hasNext();) {
+                try {
+                    i.next().removeNode2();
+                    i.remove();
+                } catch (BackingStoreException x) { }
+            }
+
+            // Now we have no descendants - it's time to die!
+            removeNodeSpi();
+            removed = true;
+            parent.enqueueNodeRemovedEvent(this);
+        }
+    }
+
+    /**
+     * Implements the <tt>name</tt> method as per the specification in
+     * {@link Preferences#name()}.
+     *
+     * <p>This implementation merely returns the name that was
+     * passed to this node's constructor.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Implements the <tt>absolutePath</tt> method as per the specification in
+     * {@link Preferences#absolutePath()}.
+     *
+     * <p>This implementation merely returns the absolute path name that
+     * was computed at the time that this node was constructed (based on
+     * the name that was passed to this node's constructor, and the names
+     * that were passed to this node's ancestors' constructors).
+     *
+     * @return this preference node's absolute path name.
+     */
+    public String absolutePath() {
+        return absolutePath;
+    }
+
+    /**
+     * Implements the <tt>isUserNode</tt> method as per the specification in
+     * {@link Preferences#isUserNode()}.
+     *
+     * <p>This implementation compares this node's root node (which is stored
+     * in a private field) with the value returned by
+     * {@link Preferences#userRoot()}.  If the two object references are
+     * identical, this method returns true.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public boolean isUserNode() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return root == Preferences.userRoot();
+            }
+            }).booleanValue();
+    }
+
+    public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+        if (pcl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] old = prefListeners;
+            prefListeners = new PreferenceChangeListener[old.length + 1];
+            System.arraycopy(old, 0, prefListeners, 0, old.length);
+            prefListeners[old.length] = pcl;
+            */
+            prefListeners.add(pcl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((prefListeners == null) || (prefListeners.length == 0))
+            if (!prefListeners.contains(pcl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] newPl =
+                new PreferenceChangeListener[prefListeners.length - 1];
+            int i = 0;
+            while (i < newPl.length && prefListeners[i] != pcl)
+                newPl[i] = prefListeners[i++];
+
+            if (i == newPl.length &&  prefListeners[i] != pcl)
+                throw new IllegalArgumentException("Listener not registered.");
+            while (i < newPl.length)
+                newPl[i] = prefListeners[++i];
+            prefListeners = newPl;
+            */
+            prefListeners.remove(pcl);
+        }
+    }
+
+    public void addNodeChangeListener(NodeChangeListener ncl) {
+        if (ncl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            if (nodeListeners == null) {
+                nodeListeners = new NodeChangeListener[1];
+                nodeListeners[0] = ncl;
+            } else {
+                NodeChangeListener[] old = nodeListeners;
+                nodeListeners = new NodeChangeListener[old.length + 1];
+                System.arraycopy(old, 0, nodeListeners, 0, old.length);
+                nodeListeners[old.length] = ncl;
+            }
+            */
+            nodeListeners.add(ncl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removeNodeChangeListener(NodeChangeListener ncl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((nodeListeners == null) || (nodeListeners.length == 0))
+            if (!nodeListeners.contains(ncl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            int i = 0;
+            while (i < nodeListeners.length && nodeListeners[i] != ncl)
+                i++;
+            if (i == nodeListeners.length)
+                throw new IllegalArgumentException("Listener not registered.");
+            NodeChangeListener[] newNl =
+                new NodeChangeListener[nodeListeners.length - 1];
+            if (i != 0)
+                System.arraycopy(nodeListeners, 0, newNl, 0, i);
+            if (i != newNl.length)
+                System.arraycopy(nodeListeners, i + 1,
+                                 newNl, i, newNl.length - i);
+            nodeListeners = newNl;
+            */
+            nodeListeners.remove(ncl);
+        }
+    }
+
+    // "SPI" METHODS
+
+    /**
+     * Put the given key-value association into this preference node.  It is
+     * guaranteed that <tt>key</tt> and <tt>value</tt> are non-null and of
+     * legal length.  Also, it is guaranteed that this node has not been
+     * removed.  (The implementor needn't check for any of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     * @param value the value
+     */
+    protected abstract void putSpi(String key, String value);
+
+    /**
+     * Return the value associated with the specified key at this preference
+     * node, or <tt>null</tt> if there is no association for this key, or the
+     * association cannot be determined at this time.  It is guaranteed that
+     * <tt>key</tt> is non-null.  Also, it is guaranteed that this node has
+     * not been removed.  (The implementor needn't check for either of these
+     * things.)
+     *
+     * <p> Generally speaking, this method should not throw an exception
+     * under any circumstances.  If, however, if it does throw an exception,
+     * the exception will be intercepted and treated as a <tt>null</tt>
+     * return value.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param key the key
+     * @return the value associated with the specified key at this preference
+     *          node, or <tt>null</tt> if there is no association for this
+     *          key, or the association cannot be determined at this time.
+     */
+    protected abstract String getSpi(String key);
+
+    /**
+     * Remove the association (if any) for the specified key at this
+     * preference node.  It is guaranteed that <tt>key</tt> is non-null.
+     * Also, it is guaranteed that this node has not been removed.
+     * (The implementor needn't check for either of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     */
+    protected abstract void removeSpi(String key);
+
+    /**
+     * Removes this preference node, invalidating it and any preferences that
+     * it contains.  The named child will have no descendants at the time this
+     * invocation is made (i.e., the {@link Preferences#removeNode()} method
+     * invokes this method repeatedly in a bottom-up fashion, removing each of
+     * a node's descendants before removing the node itself).
+     *
+     * <p>This method is invoked with the lock held on this node and its
+     * parent (and all ancestors that are being removed as a
+     * result of a single invocation to {@link Preferences#removeNode()}).
+     *
+     * <p>The removal of a node needn't become persistent until the
+     * <tt>flush</tt> method is invoked on this node (or an ancestor).
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #removeNode()}
+     * invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void removeNodeSpi() throws BackingStoreException;
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)  It is guaranteed that this node has not
+     * been removed.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #keys()} invocation.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] keysSpi() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node.  (The
+     * returned array will be of size zero if this node has no children.)
+     * This method need not return the names of any nodes already cached,
+     * but may do so without harm.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #childrenNames()}
+     * invocation.
+     *
+     * @return an array containing the names of the children of this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] childrenNamesSpi()
+        throws BackingStoreException;
+
+    /**
+     * Returns the named child if it exists, or <tt>null</tt> if it does not.
+     * It is guaranteed that <tt>nodeName</tt> is non-null, non-empty,
+     * does not contain the slash character ('/'), and is no longer than
+     * {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed
+     * that this node has not been removed.  (The implementor needn't check
+     * for any of these things if he chooses to override this method.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #childSpi} after the
+     * last time that it was removed.  In other words, a cached value will
+     * always be used in preference to invoking this method.  (The implementor
+     * needn't maintain his own cache of previously returned children if he
+     * chooses to override this method.)
+     *
+     * <p>This implementation obtains this preference node's lock, invokes
+     * {@link #childrenNames()} to get an array of the names of this node's
+     * children, and iterates over the array comparing the name of each child
+     * with the specified node name.  If a child node has the correct name,
+     * the {@link #childSpi(String)} method is invoked and the resulting
+     * node is returned.  If the iteration completes without finding the
+     * specified name, <tt>null</tt> is returned.
+     *
+     * @param nodeName name of the child to be searched for.
+     * @return the named child if it exists, or null if it does not.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected AbstractPreferences getChild(String nodeName)
+            throws BackingStoreException {
+        synchronized(lock) {
+            // assert kidCache.get(nodeName)==null;
+            String[] kidNames = childrenNames();
+            for (int i=0; i<kidNames.length; i++)
+                if (kidNames[i].equals(nodeName))
+                    return childSpi(kidNames[i]);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the named child of this preference node, creating it if it does
+     * not already exist.  It is guaranteed that <tt>name</tt> is non-null,
+     * non-empty, does not contain the slash character ('/'), and is no longer
+     * than {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed that
+     * this node has not been removed.  (The implementor needn't check for any
+     * of these things.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #getChild(String)}
+     * after the last time that it was removed.  In other words, a cached
+     * value will always be used in preference to invoking this method.
+     * Subclasses need not maintain their own cache of previously returned
+     * children.
+     *
+     * <p>The implementer must ensure that the returned node has not been
+     * removed.  If a like-named child of this node was previously removed, the
+     * implementer must return a newly constructed <tt>AbstractPreferences</tt>
+     * node; once removed, an <tt>AbstractPreferences</tt> node
+     * cannot be "resuscitated."
+     *
+     * <p>If this method causes a node to be created, this node is not
+     * guaranteed to be persistent until the <tt>flush</tt> method is
+     * invoked on this node or one of its ancestors (or descendants).
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param name The name of the child node to return, relative to
+     *        this preference node.
+     * @return The named child node.
+     */
+    protected abstract AbstractPreferences childSpi(String name);
+
+    /**
+     * Returns the absolute path name of this preferences node.
+     */
+    public String toString() {
+        return (this.isUserNode() ? "User" : "System") +
+               " Preference Node: " + this.absolutePath();
+    }
+
+    /**
+     * Implements the <tt>sync</tt> method as per the specification in
+     * {@link Preferences#sync()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes syncSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling syncSpi() on each node in
+     * the subTree while only that node is locked. Note that syncSpi() is
+     * invoked top-down.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public void sync() throws BackingStoreException {
+        sync2();
+    }
+
+    private void sync2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed");
+            syncSpi();
+            cachedKids = cachedChildren();
+        }
+
+        for (int i=0; i<cachedKids.length; i++)
+            cachedKids[i].sync2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to synchronize any cached preferences stored at this node
+     * with any stored in the backing store.  (It is perfectly possible that
+     * this node does not exist on the backing store, either because it has
+     * been deleted by another VM, or because it has not yet been created.)
+     * Note that this method should <i>not</i> synchronize the preferences in
+     * any subnodes of this node.  If the backing store naturally syncs an
+     * entire subtree at once, the implementer is encouraged to override
+     * sync(), rather than merely overriding this method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #sync()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void syncSpi() throws BackingStoreException;
+
+    /**
+     * Implements the <tt>flush</tt> method as per the specification in
+     * {@link Preferences#flush()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes flushSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling flushSpi() on each node in
+     * the subTree while only that node is locked. Note that flushSpi() is
+     * invoked top-down.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see #flush()
+     */
+    public void flush() throws BackingStoreException {
+        flush2();
+    }
+
+    private void flush2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            flushSpi();
+            if(removed)
+                return;
+            cachedKids = cachedChildren();
+        }
+
+        for (int i = 0; i < cachedKids.length; i++)
+            cachedKids[i].flush2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to force any cached changes in the contents of this
+     * preference node to the backing store, guaranteeing their persistence.
+     * (It is perfectly possible that this node does not exist on the backing
+     * store, either because it has been deleted by another VM, or because it
+     * has not yet been created.)  Note that this method should <i>not</i>
+     * flush the preferences in any subnodes of this node.  If the backing
+     * store naturally flushes an entire subtree at once, the implementer is
+     * encouraged to override flush(), rather than merely overriding this
+     * method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #flush()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void flushSpi() throws BackingStoreException;
+
+    /**
+     * Returns <tt>true</tt> iff this node (or an ancestor) has been
+     * removed with the {@link #removeNode()} method.  This method
+     * locks this node prior to returning the contents of the private
+     * field used to track this state.
+     *
+     * @return <tt>true</tt> iff this node (or an ancestor) has been
+     *       removed with the {@link #removeNode()} method.
+     */
+    protected boolean isRemoved() {
+        synchronized(lock) {
+            return removed;
+        }
+    }
+
+    /**
+     * Queue of pending notification events.  When a preference or node
+     * change event for which there are one or more listeners occurs,
+     * it is placed on this queue and the queue is notified.  A background
+     * thread waits on this queue and delivers the events.  This decouples
+     * event delivery from preference activity, greatly simplifying
+     * locking and reducing opportunity for deadlock.
+     */
+    private static final List<EventObject> eventQueue = new LinkedList<>();
+
+    /**
+     * These two classes are used to distinguish NodeChangeEvents on
+     * eventQueue so the event dispatch thread knows whether to call
+     * childAdded or childRemoved.
+     */
+    private class NodeAddedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = -6743557530157328528L;
+        NodeAddedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+    private class NodeRemovedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = 8735497392918824837L;
+        NodeRemovedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+
+    /**
+     * A single background thread ("the event notification thread") monitors
+     * the event queue and delivers events that are placed on the queue.
+     */
+    private static class EventDispatchThread extends Thread {
+        public void run() {
+            while(true) {
+                // Wait on eventQueue till an event is present
+                EventObject event = null;
+                synchronized(eventQueue) {
+                    try {
+                        while (eventQueue.isEmpty())
+                            eventQueue.wait();
+                        event = eventQueue.remove(0);
+                    } catch (InterruptedException e) {
+                        // XXX Log "Event dispatch thread interrupted. Exiting"
+                        return;
+                    }
+                }
+
+                // Now we have event & hold no locks; deliver evt to listeners
+                AbstractPreferences src=(AbstractPreferences)event.getSource();
+                if (event instanceof PreferenceChangeEvent) {
+                    PreferenceChangeEvent pce = (PreferenceChangeEvent)event;
+                    PreferenceChangeListener[] listeners = src.prefListeners();
+                    for (int i=0; i<listeners.length; i++)
+                        listeners[i].preferenceChange(pce);
+                } else {
+                    NodeChangeEvent nce = (NodeChangeEvent)event;
+                    NodeChangeListener[] listeners = src.nodeListeners();
+                    if (nce instanceof NodeAddedEvent) {
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childAdded(nce);
+                    } else {
+                        // assert nce instanceof NodeRemovedEvent;
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childRemoved(nce);
+                    }
+                }
+            }
+        }
+    }
+
+    private static Thread eventDispatchThread = null;
+
+    /**
+     * This method starts the event dispatch thread the first time it
+     * is called.  The event dispatch thread will be started only
+     * if someone registers a listener.
+     */
+    private static synchronized void startEventDispatchThreadIfNecessary() {
+        if (eventDispatchThread == null) {
+            // XXX Log "Starting event dispatch thread"
+            eventDispatchThread = new EventDispatchThread();
+            eventDispatchThread.setDaemon(true);
+            eventDispatchThread.start();
+        }
+    }
+
+    // BEGIN Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // Changed documentation.
+    /*
+    /**
+     * Return this node's preference/node change listeners.  Even though
+     * we're using a copy-on-write lists, we use synchronized accessors to
+     * ensure information transmission from the writing thread to the
+     * reading thread.
+     *
+    */
+    /**
+     * Return this node's preference/node change listeners. All accesses to prefListeners
+     * and nodeListeners are guarded by |lock|. We return a copy of the list so that the
+     * EventQueue thread will iterate over a fixed snapshot of the listeners at the time of
+     * this call.
+     */
+    // END Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    PreferenceChangeListener[] prefListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return prefListeners;
+            return prefListeners.toArray(new PreferenceChangeListener[prefListeners.size()]);
+        }
+    }
+    NodeChangeListener[] nodeListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return nodeListeners;
+            return nodeListeners.toArray(new NodeChangeListener[nodeListeners.size()]);
+        }
+    }
+
+    /**
+     * Enqueue a preference change event for delivery to registered
+     * preference change listeners unless there are no registered
+     * listeners.  Invoked with this.lock held.
+     */
+    private void enqueuePreferenceChangeEvent(String key, String newValue) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (prefListeners.length != 0) {
+        if (!prefListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new PreferenceChangeEvent(this, key, newValue));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node added" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeAddedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeAddedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node removed" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeRemovedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeRemovedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Implements the <tt>exportNode</tt> method as per the specification in
+     * {@link Preferences#exportNode(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportNode(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, false);
+    }
+
+    /**
+     * Implements the <tt>exportSubtree</tt> method as per the specification in
+     * {@link Preferences#exportSubtree(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, true);
+    }
+}
diff --git a/android-35/java/util/prefs/BackingStoreException.java b/android-35/java/util/prefs/BackingStoreException.java
new file mode 100644
index 0000000..0bce9c6
--- /dev/null
+++ b/android-35/java/util/prefs/BackingStoreException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that a preferences operation could not complete because
+ * of a failure in the backing store, or a failure to contact the backing
+ * store.
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public class BackingStoreException extends Exception {
+    /**
+     * Constructs a BackingStoreException with the specified detail message.
+     *
+     * @param s the detail message.
+     */
+    public BackingStoreException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a BackingStoreException with the specified cause.
+     *
+     * @param cause the cause
+     */
+    public BackingStoreException(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = 859796500401108469L;
+}
diff --git a/android-35/java/util/prefs/Base64.java b/android-35/java/util/prefs/Base64.java
new file mode 100644
index 0000000..c0d8d53
--- /dev/null
+++ b/android-35/java/util/prefs/Base64.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Static methods for translating Base64 encoded strings to byte arrays
+ * and vice-versa.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+class Base64 {
+    /**
+     * Translates the specified byte array into a Base64 string as per
+     * Preferences.put(byte[]).
+     */
+    static String byteArrayToBase64(byte[] a) {
+        return byteArrayToBase64(a, false);
+    }
+
+    /**
+     * Translates the specified byte array into an "alternate representation"
+     * Base64 string.  This non-standard variant uses an alphabet that does
+     * not contain the uppercase alphabetic characters, which makes it
+     * suitable for use in situations where case-folding occurs.
+     */
+    static String byteArrayToAltBase64(byte[] a) {
+        return byteArrayToBase64(a, true);
+    }
+
+    private static String byteArrayToBase64(byte[] a, boolean alternate) {
+        int aLen = a.length;
+        int numFullGroups = aLen/3;
+        int numBytesInPartialGroup = aLen - 3*numFullGroups;
+        int resultLen = 4*((aLen + 2)/3);
+        StringBuffer result = new StringBuffer(resultLen);
+        char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64);
+
+        // Translate all full groups from byte array elements to Base64
+        int inCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int byte0 = a[inCursor++] & 0xff;
+            int byte1 = a[inCursor++] & 0xff;
+            int byte2 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+            result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
+            result.append(intToAlpha[byte2 & 0x3f]);
+        }
+
+        // Translate partial group if present
+        if (numBytesInPartialGroup != 0) {
+            int byte0 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            if (numBytesInPartialGroup == 1) {
+                result.append(intToAlpha[(byte0 << 4) & 0x3f]);
+                result.append("==");
+            } else {
+                // assert numBytesInPartialGroup == 2;
+                int byte1 = a[inCursor++] & 0xff;
+                result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+                result.append(intToAlpha[(byte1 << 2)&0x3f]);
+                result.append('=');
+            }
+        }
+        // assert inCursor == a.length;
+        // assert result.length() == resultLen;
+        return result.toString();
+    }
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Base64 Alphabet" equivalents as specified
+     * in Table 1 of RFC 2045.
+     */
+    private static final char intToBase64[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Alternate Base64 Alphabet" equivalents.
+     * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045.
+     * This alternate alphabet does not use the capital letters.  It is
+     * designed for use in environments where "case folding" occurs.
+     */
+    private static final char intToAltBase64[] = {
+        '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':',
+        ';', '<', '>', '@', '[', ']', '^',  '`', '_', '{', '|', '}', '~',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't',  'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6',  '7', '8', '9', '+', '?'
+    };
+
+    /**
+     * Translates the specified Base64 string (as per Preferences.get(byte[]))
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64
+     *        string.
+     */
+    static byte[] base64ToByteArray(String s) {
+        return base64ToByteArray(s, false);
+    }
+
+    /**
+     * Translates the specified "alternate representation" Base64 string
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException
+     *        if <tt>s</tt> is not a valid alternate representation
+     *        Base64 string.
+     */
+    static byte[] altBase64ToByteArray(String s) {
+        return base64ToByteArray(s, true);
+    }
+
+    private static byte[] base64ToByteArray(String s, boolean alternate) {
+        byte[] alphaToInt = (alternate ?  altBase64ToInt : base64ToInt);
+        int sLen = s.length();
+        int numGroups = sLen/4;
+        if (4*numGroups != sLen)
+            throw new IllegalArgumentException(
+                "String length must be a multiple of four.");
+        int missingBytesInLastGroup = 0;
+        int numFullGroups = numGroups;
+        if (sLen != 0) {
+            if (s.charAt(sLen-1) == '=') {
+                missingBytesInLastGroup++;
+                numFullGroups--;
+            }
+            if (s.charAt(sLen-2) == '=')
+                missingBytesInLastGroup++;
+        }
+        byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
+
+        // Translate all full groups from base64 to byte array elements
+        int inCursor = 0, outCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+            result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            result[outCursor++] = (byte) ((ch2 << 6) | ch3);
+        }
+
+        // Translate partial group, if present
+        if (missingBytesInLastGroup != 0) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+
+            if (missingBytesInLastGroup == 1) {
+                int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+                result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            }
+        }
+        // assert inCursor == s.length()-missingBytesInLastGroup;
+        // assert outCursor == result.length;
+        return result;
+    }
+
+    /**
+     * Translates the specified character, which is assumed to be in the
+     * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException if
+     *        c is not in the Base64 Alphabet.
+     */
+    private static int base64toInt(char c, byte[] alphaToInt) {
+        int result = alphaToInt[c];
+        if (result < 0)
+            throw new IllegalArgumentException("Illegal character " + c);
+        return result;
+    }
+
+    /**
+     * This array is a lookup table that translates unicode characters
+     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+     * into their 6-bit positive integer equivalents.  Characters that
+     * are not in the Base64 alphabet but fall within the bounds of the
+     * array are translated to -1.
+     */
+    private static final byte base64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    /**
+     * This array is the analogue of base64ToInt, but for the nonstandard
+     * variant that avoids the use of uppercase alphabetic characters.
+     */
+    private static final byte altBase64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
+        2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57,
+        58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33,
+        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+        51, 22, 23, 24, 25
+    };
+
+    public static void main(String args[]) {
+        int numRuns  = Integer.parseInt(args[0]);
+        int numBytes = Integer.parseInt(args[1]);
+        java.util.Random rnd = new java.util.Random();
+        for (int i=0; i<numRuns; i++) {
+            for (int j=0; j<numBytes; j++) {
+                byte[] arr = new byte[j];
+                for (int k=0; k<j; k++)
+                    arr[k] = (byte)rnd.nextInt();
+
+                String s = byteArrayToBase64(arr);
+                byte [] b = base64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Dismal failure!");
+
+                s = byteArrayToAltBase64(arr);
+                b = altBase64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Alternate dismal failure!");
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/prefs/FileSystemPreferences.java b/android-35/java/util/prefs/FileSystemPreferences.java
new file mode 100644
index 0000000..9976aeb
--- /dev/null
+++ b/android-35/java/util/prefs/FileSystemPreferences.java
@@ -0,0 +1,998 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+import sun.util.logging.PlatformLogger;
+
+// Android-changed: @hide.
+/**
+ * Preferences implementation for Unix.  Preferences are stored in the file
+ * system, with one directory per preferences node.  All of the preferences
+ * at each node are stored in a single file.  Atomic file system operations
+ * (e.g. File.renameTo) are used to ensure integrity.  An in-memory cache of
+ * the "explored" portion of the tree is maintained for performance, and
+ * written back to the disk periodically.  File-locking is used to ensure
+ * reasonable behavior when multiple VMs are running at the same time.
+ * (The file lock is obtained only for sync(), flush() and removeNode().)
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ *
+ * @hide
+ */
+public class FileSystemPreferences extends AbstractPreferences {
+    /**
+     * Returns logger for error messages. Backing store exceptions are logged at
+     * WARNING level.
+     */
+    private static PlatformLogger getLogger() {
+        return PlatformLogger.getLogger("java.util.prefs");
+    }
+
+    /**
+     * Directory for system preferences.
+     */
+    private static File systemRootDir;
+
+    /*
+     * Flag, indicating whether systemRoot  directory is writable
+     */
+    private static boolean isSystemRootWritable;
+
+    /**
+     * Directory for user preferences.
+     */
+    private static File userRootDir;
+
+    /*
+     * Flag, indicating whether userRoot  directory is writable
+     */
+    private static boolean isUserRootWritable;
+
+   /**
+     * The user root.
+     */
+    static Preferences userRoot = null;
+
+    static synchronized Preferences getUserRoot() {
+        if (userRoot == null) {
+            setupUserRoot();
+            userRoot = new FileSystemPreferences(true);
+        }
+        return userRoot;
+    }
+
+    private static void setupUserRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                userRootDir =
+                      new File(System.getProperty("java.util.prefs.userRoot",
+                      System.getProperty("user.home")), ".java/.userPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!userRootDir.exists()) {
+                    if (userRootDir.mkdirs()) {
+                        try {
+                            chmod(userRootDir.getCanonicalPath(), USER_RWX);
+                        } catch (IOException e) {
+                            getLogger().warning("Could not change permissions" +
+                                " on userRoot directory. ");
+                        }
+                        getLogger().info("Created user preferences directory.");
+                    }
+                    else
+                        getLogger().warning("Couldn't create user preferences" +
+                        " directory. User preferences are unusable.");
+                }
+                isUserRootWritable = userRootDir.canWrite();
+                String USER_NAME = System.getProperty("user.name");
+                userLockFile = new File (userRootDir,".user.lock." + USER_NAME);
+                userRootModFile = new File (userRootDir,
+                                               ".userRootModFile." + USER_NAME);
+                if (!userRootModFile.exists())
+                try {
+                    // create if does not exist.
+                    userRootModFile.createNewFile();
+                    // Only user can read/write userRootModFile.
+                    int result = chmod(userRootModFile.getCanonicalPath(),
+                                                               USER_READ_WRITE);
+                    if (result !=0)
+                        getLogger().warning("Problem creating userRoot " +
+                            "mod file. Chmod failed on " +
+                             userRootModFile.getCanonicalPath() +
+                             " Unix error code " + result);
+                } catch (IOException e) {
+                    getLogger().warning(e.toString());
+                }
+                userRootModTime = userRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * The system root.
+     */
+    static Preferences systemRoot;
+
+    static synchronized Preferences getSystemRoot() {
+        if (systemRoot == null) {
+            setupSystemRoot();
+            systemRoot = new FileSystemPreferences(false);
+        }
+        return systemRoot;
+    }
+
+    private static void setupSystemRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                String systemPrefsDirName =
+                  System.getProperty("java.util.prefs.systemRoot","/etc/.java");
+                systemRootDir =
+                     new File(systemPrefsDirName, ".systemPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!systemRootDir.exists()) {
+                    // system root does not exist in /etc/.java
+                    // Switching  to java.home
+                    systemRootDir =
+                                  new File(System.getProperty("java.home"),
+                                                            ".systemPrefs");
+                    if (!systemRootDir.exists()) {
+                        if (systemRootDir.mkdirs()) {
+                            getLogger().info(
+                                "Created system preferences directory "
+                                + "in java.home.");
+                            try {
+                                chmod(systemRootDir.getCanonicalPath(),
+                                                          USER_RWX_ALL_RX);
+                            } catch (IOException e) {
+                            }
+                        } else {
+                            getLogger().warning("Could not create "
+                                + "system preferences directory. System "
+                                + "preferences are unusable.");
+                        }
+                    }
+                }
+                isSystemRootWritable = systemRootDir.canWrite();
+                systemLockFile = new File(systemRootDir, ".system.lock");
+                systemRootModFile =
+                               new File (systemRootDir,".systemRootModFile");
+                if (!systemRootModFile.exists() && isSystemRootWritable)
+                try {
+                    // create if does not exist.
+                    systemRootModFile.createNewFile();
+                    int result = chmod(systemRootModFile.getCanonicalPath(),
+                                                          USER_RW_ALL_READ);
+                    if (result !=0)
+                        getLogger().warning("Chmod failed on " +
+                               systemRootModFile.getCanonicalPath() +
+                              " Unix error code " + result);
+                } catch (IOException e) { getLogger().warning(e.toString());
+                }
+                systemRootModTime = systemRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * Unix user write/read permission
+     */
+    private static final int USER_READ_WRITE = 0600;
+
+    private static final int USER_RW_ALL_READ = 0644;
+
+
+    private static final int USER_RWX_ALL_RX = 0755;
+
+    private static final int USER_RWX = 0700;
+
+    /**
+     * The lock file for the user tree.
+     */
+    static File userLockFile;
+
+
+
+    /**
+     * The lock file for the system tree.
+     */
+    static File systemLockFile;
+
+    /**
+     * Unix lock handle for userRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int userRootLockHandle = 0;
+
+    /**
+     * Unix lock handle for systemRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int systemRootLockHandle = 0;
+
+    /**
+     * The directory representing this preference node.  There is no guarantee
+     * that this directory exits, as another VM can delete it at any time
+     * that it (the other VM) holds the file-lock.  While the root node cannot
+     * be deleted, it may not yet have been created, or the underlying
+     * directory could have been deleted accidentally.
+     */
+    private final File dir;
+
+    /**
+     * The file representing this preference node's preferences.
+     * The file format is undocumented, and subject to change
+     * from release to release, but I'm sure that you can figure
+     * it out if you try real hard.
+     */
+    private final File prefsFile;
+
+    /**
+     * A temporary file used for saving changes to preferences.  As part of
+     * the sync operation, changes are first saved into this file, and then
+     * atomically renamed to prefsFile.  This results in an atomic state
+     * change from one valid set of preferences to another.  The
+     * the file-lock is held for the duration of this transformation.
+     */
+    private final File tmpFile;
+
+    /**
+     * File, which keeps track of global modifications of userRoot.
+     */
+    private static  File userRootModFile;
+
+    /**
+     * Flag, which indicated whether userRoot was modified by another VM
+     */
+    private static boolean isUserRootModified = false;
+
+    /**
+     * Keeps track of userRoot modification time. This time is reset to
+     * zero after UNIX reboot, and is increased by 1 second each time
+     * userRoot is modified.
+     */
+    private static long userRootModTime;
+
+
+    /*
+     * File, which keeps track of global modifications of systemRoot
+     */
+    private static File systemRootModFile;
+    /*
+     * Flag, which indicates whether systemRoot was modified by another VM
+     */
+    private static boolean isSystemRootModified = false;
+
+    /**
+     * Keeps track of systemRoot modification time. This time is reset to
+     * zero after system reboot, and is increased by 1 second each time
+     * systemRoot is modified.
+     */
+    private static long systemRootModTime;
+
+    /**
+     * Locally cached preferences for this node (includes uncommitted
+     * changes).  This map is initialized with from disk when the first get or
+     * put operation occurs on this node.  It is synchronized with the
+     * corresponding disk file (prefsFile) by the sync operation.  The initial
+     * value is read *without* acquiring the file-lock.
+     */
+    private Map<String, String> prefsCache = null;
+
+    /**
+     * The last modification time of the file backing this node at the time
+     * that prefCache was last synchronized (or initially read).  This
+     * value is set *before* reading the file, so it's conservative; the
+     * actual timestamp could be (slightly) higher.  A value of zero indicates
+     * that we were unable to initialize prefsCache from the disk, or
+     * have not yet attempted to do so.  (If prefsCache is non-null, it
+     * indicates the former; if it's null, the latter.)
+     */
+    private long lastSyncTime = 0;
+
+   /**
+    * Unix error code for locked file.
+    */
+    private static final int EAGAIN = 11;
+
+   /**
+    * Unix error code for denied access.
+    */
+    private static final int EACCES = 13;
+
+    /* Used to interpret results of native functions */
+    private static final int LOCK_HANDLE = 0;
+    private static final int ERROR_CODE = 1;
+
+    /**
+     * A list of all uncommitted preference changes.  The elements in this
+     * list are of type PrefChange.  If this node is concurrently modified on
+     * disk by another VM, the two sets of changes are merged when this node
+     * is sync'ed by overwriting our prefsCache with the preference map last
+     * written out to disk (by the other VM), and then replaying this change
+     * log against that map.  The resulting map is then written back
+     * to the disk.
+     */
+    final List<Change> changeLog = new ArrayList<>();
+
+    /**
+     * Represents a change to a preference.
+     */
+    private abstract class Change {
+        /**
+         * Reapplies the change to prefsCache.
+         */
+        abstract void replay();
+    };
+
+    /**
+     * Represents a preference put.
+     */
+    private class Put extends Change {
+        String key, value;
+
+        Put(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        void replay() {
+            prefsCache.put(key, value);
+        }
+    }
+
+    /**
+     * Represents a preference remove.
+     */
+    private class Remove extends Change {
+        String key;
+
+        Remove(String key) {
+            this.key = key;
+        }
+
+        void replay() {
+            prefsCache.remove(key);
+        }
+    }
+
+    /**
+     * Represents the creation of this node.
+     */
+    private class NodeCreate extends Change {
+        /**
+         * Performs no action, but the presence of this object in changeLog
+         * will force the node and its ancestors to be made permanent at the
+         * next sync.
+         */
+        void replay() {
+        }
+    }
+
+    /**
+     * NodeCreate object for this node.
+     */
+    NodeCreate nodeCreate = null;
+
+    /**
+     * Replay changeLog against prefsCache.
+     */
+    private void replayChanges() {
+        for (int i = 0, n = changeLog.size(); i<n; i++)
+            changeLog.get(i).replay();
+    }
+
+    static {
+        // Add shutdown hook to flush cached prefs on normal termination
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                syncWorld();
+            }
+        });
+    }
+
+    private static void syncWorld() {
+        /*
+         * Synchronization necessary because userRoot and systemRoot are
+         * lazily initialized.
+         */
+        Preferences userRt;
+        Preferences systemRt;
+        synchronized(FileSystemPreferences.class) {
+            userRt   = userRoot;
+            systemRt = systemRoot;
+        }
+
+        try {
+            if (userRt != null)
+                userRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush user prefs: " + e);
+        }
+
+        try {
+            if (systemRt != null)
+                systemRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush system prefs: " + e);
+        }
+    }
+
+    private final boolean isUserNode;
+
+    /**
+     * Special constructor for roots (both user and system).  This constructor
+     * will only be called twice, by the static initializer.
+     */
+    private FileSystemPreferences(boolean user) {
+        super(null, "");
+        isUserNode = user;
+        dir = (user ? userRootDir: systemRootDir);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile   = new File(dir, "prefs.tmp");
+    }
+
+    /** @hide for unit testing only */
+    // Android-added constructor for testing.
+    public FileSystemPreferences(String path, File lockFile, boolean isUserNode) {
+        super(null, "");
+        this.isUserNode = isUserNode;
+        this.dir = new File(path);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile = new File(dir, "prefs.tmp");
+        newNode = !dir.exists();
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+
+        if (isUserNode) {
+            userLockFile = lockFile;
+            userRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        } else {
+            systemLockFile = lockFile;
+            systemRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        }
+    }
+
+    /**
+     * Construct a new FileSystemPreferences instance with the specified
+     * parent node and name.  This constructor, called from childSpi,
+     * is used to make every node except for the two //roots.
+     */
+    private FileSystemPreferences(FileSystemPreferences parent, String name) {
+        super(parent, name);
+        isUserNode = parent.isUserNode;
+        dir  = new File(parent.dir, dirName(name));
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile  = new File(dir, "prefs.tmp");
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                newNode = !dir.exists();
+                return null;
+            }
+        });
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+    }
+
+    public boolean isUserNode() {
+        return isUserNode;
+    }
+
+    protected void putSpi(String key, String value) {
+        initCacheIfNecessary();
+        changeLog.add(new Put(key, value));
+        prefsCache.put(key, value);
+    }
+
+    protected String getSpi(String key) {
+        initCacheIfNecessary();
+        return prefsCache.get(key);
+    }
+
+    protected void removeSpi(String key) {
+        initCacheIfNecessary();
+        changeLog.add(new Remove(key));
+        prefsCache.remove(key);
+    }
+
+    /**
+     * Initialize prefsCache if it has yet to be initialized.  When this method
+     * returns, prefsCache will be non-null.  If the data was successfully
+     * read from the file, lastSyncTime will be updated.  If prefsCache was
+     * null, but it was impossible to read the file (because it didn't
+     * exist or for any other reason) prefsCache will be initialized to an
+     * empty, modifiable Map, and lastSyncTime remain zero.
+     */
+    private void initCacheIfNecessary() {
+        if (prefsCache != null)
+            return;
+
+        try {
+            loadCache();
+        } catch(Exception e) {
+            // assert lastSyncTime == 0;
+            prefsCache = new TreeMap<>();
+        }
+    }
+
+    /**
+     * Attempt to load prefsCache from the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will typically
+     * correspond to the data loaded into the map, but it may be less,
+     * if another VM is updating this node concurrently).  If the attempt
+     * fails, a BackingStoreException is thrown and both prefsCache and
+     * lastSyncTime are unaffected by the call.
+     */
+    private void loadCache() throws BackingStoreException {
+        Map<String, String> m = new TreeMap<>();
+        long newLastSyncTime = 0;
+        try {
+            newLastSyncTime = prefsFile.lastModified();
+            try (FileInputStream fis = new FileInputStream(prefsFile)) {
+                XmlSupport.importMap(fis, m);
+            }
+        } catch(Exception e) {
+            if (e instanceof InvalidPreferencesFormatException) {
+                getLogger().warning("Invalid preferences format in "
+                                    +  prefsFile.getPath());
+                prefsFile.renameTo( new File(
+                                             prefsFile.getParentFile(),
+                                             "IncorrectFormatPrefs.xml"));
+                m = new TreeMap<>();
+            } else if (e instanceof FileNotFoundException) {
+                getLogger().warning("Prefs file removed in background "
+                                    + prefsFile.getPath());
+            } else {
+                // Android-added: This exception may be ignored by some callers,
+                // added a logger entry to prevent omitting it completely.
+                getLogger().warning("Exception while reading cache: "
+                                    + e.getMessage());
+                throw new BackingStoreException(e);
+            }
+        }
+        // Attempt succeeded; update state
+        prefsCache = m;
+        lastSyncTime = newLastSyncTime;
+    }
+
+    /**
+     * Attempt to write back prefsCache to the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will correspond
+     * exactly to the data thust written back, as we hold the file lock, which
+     * prevents a concurrent write.  If the attempt fails, a
+     * BackingStoreException is thrown and both the backing store (prefsFile)
+     * and lastSyncTime will be unaffected by this call.  This call will
+     * NEVER leave prefsFile in a corrupt state.
+     */
+    private void writeBackCache() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    try {
+                        if (!dir.exists() && !dir.mkdirs())
+                            throw new BackingStoreException(dir +
+                                                             " create failed.");
+                        try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
+                            XmlSupport.exportMap(fos, prefsCache);
+                        }
+                        if (!tmpFile.renameTo(prefsFile))
+                            throw new BackingStoreException("Can't rename " +
+                            tmpFile + " to " + prefsFile);
+                    } catch(Exception e) {
+                        if (e instanceof BackingStoreException)
+                            throw (BackingStoreException)e;
+                        throw new BackingStoreException(e);
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    protected String[] keysSpi() {
+        initCacheIfNecessary();
+        return prefsCache.keySet().toArray(new String[prefsCache.size()]);
+    }
+
+    protected String[] childrenNamesSpi() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<String[]>() {
+                public String[] run() {
+                    List<String> result = new ArrayList<>();
+                    File[] dirContents = dir.listFiles();
+                    if (dirContents != null) {
+                        for (int i = 0; i < dirContents.length; i++)
+                            if (dirContents[i].isDirectory())
+                                result.add(nodeName(dirContents[i].getName()));
+                    }
+                    return result.toArray(EMPTY_STRING_ARRAY);
+               }
+            });
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    protected AbstractPreferences childSpi(String name) {
+        return new FileSystemPreferences(this, name);
+    }
+
+    public void removeNode() throws BackingStoreException {
+        synchronized (isUserNode()? userLockFile: systemLockFile) {
+            // to remove a node we need an exclusive lock
+            if (!lockFile(false))
+                throw(new BackingStoreException("Couldn't get file lock."));
+           try {
+                super.removeNode();
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    /**
+     * Called with file lock held (in addition to node locks).
+     */
+    protected void removeNodeSpi() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    if (changeLog.contains(nodeCreate)) {
+                        changeLog.remove(nodeCreate);
+                        nodeCreate = null;
+                        return null;
+                    }
+                    if (!dir.exists())
+                        return null;
+                    prefsFile.delete();
+                    tmpFile.delete();
+                    // dir should be empty now.  If it's not, empty it
+                    File[] junk = dir.listFiles();
+                    if (junk.length != 0) {
+                        getLogger().warning(
+                           "Found extraneous files when removing node: "
+                            + Arrays.asList(junk));
+                        for (int i=0; i<junk.length; i++)
+                            junk[i].delete();
+                    }
+                    if (!dir.delete())
+                        throw new BackingStoreException("Couldn't delete dir: "
+                                                                         + dir);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    public synchronized void sync() throws BackingStoreException {
+        boolean userNode = isUserNode();
+        boolean shared;
+
+        if (userNode) {
+            shared = false; /* use exclusive lock for user prefs */
+        } else {
+            /* if can write to system root, use exclusive lock.
+               otherwise use shared lock. */
+            shared = !isSystemRootWritable;
+        }
+        synchronized (isUserNode()? userLockFile:systemLockFile) {
+           if (!lockFile(shared))
+               throw(new BackingStoreException("Couldn't get file lock."));
+           final Long newModTime =
+                AccessController.doPrivileged(
+                    new PrivilegedAction<Long>() {
+               public Long run() {
+                   long nmt;
+                   if (isUserNode()) {
+                       nmt = userRootModFile.lastModified();
+                       isUserRootModified = userRootModTime == nmt;
+                   } else {
+                       nmt = systemRootModFile.lastModified();
+                       isSystemRootModified = systemRootModTime == nmt;
+                   }
+                   return new Long(nmt);
+               }
+           });
+           try {
+               super.sync();
+               AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                   public Void run() {
+                   if (isUserNode()) {
+                       userRootModTime = newModTime.longValue() + 1000;
+                       userRootModFile.setLastModified(userRootModTime);
+                   } else {
+                       systemRootModTime = newModTime.longValue() + 1000;
+                       systemRootModFile.setLastModified(systemRootModTime);
+                   }
+                   return null;
+                   }
+               });
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    protected void syncSpi() throws BackingStoreException {
+        syncSpiPrivileged();
+    }
+
+    private void syncSpiPrivileged() throws BackingStoreException {
+        if (isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        if (prefsCache == null)
+            return;  // We've never been used, don't bother syncing
+        long lastModifiedTime;
+        if ((isUserNode() ? isUserRootModified : isSystemRootModified)) {
+            lastModifiedTime = prefsFile.lastModified();
+            if (lastModifiedTime  != lastSyncTime) {
+                // Prefs at this node were externally modified; read in node and
+                // playback any local mods since last sync
+                loadCache();
+                replayChanges();
+                lastSyncTime = lastModifiedTime;
+            }
+        } else if (lastSyncTime != 0 && !dir.exists()) {
+            // This node was removed in the background.  Playback any changes
+            // against a virgin (empty) Map.
+            prefsCache = new TreeMap<>();
+            replayChanges();
+        }
+        if (!changeLog.isEmpty()) {
+            writeBackCache();  // Creates directory & file if necessary
+           /*
+            * Attempt succeeded; it's barely possible that the call to
+            * lastModified might fail (i.e., return 0), but this would not
+            * be a disaster, as lastSyncTime is allowed to lag.
+            */
+            lastModifiedTime = prefsFile.lastModified();
+            /* If lastSyncTime did not change, or went back
+             * increment by 1 second. Since we hold the lock
+             * lastSyncTime always monotonically encreases in the
+             * atomic sense.
+             */
+            if (lastSyncTime <= lastModifiedTime) {
+                lastSyncTime = lastModifiedTime + 1000;
+                prefsFile.setLastModified(lastSyncTime);
+            }
+            changeLog.clear();
+        }
+    }
+
+    public void flush() throws BackingStoreException {
+        if (isRemoved())
+            return;
+        sync();
+    }
+
+    protected void flushSpi() throws BackingStoreException {
+        // assert false;
+    }
+
+    /**
+     * Returns true if the specified character is appropriate for use in
+     * Unix directory names.  A character is appropriate if it's a printable
+     * ASCII character (> 0x1f && < 0x7f) and unequal to slash ('/', 0x2f),
+     * dot ('.', 0x2e), or underscore ('_', 0x5f).
+     */
+    private static boolean isDirChar(char ch) {
+        return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.' && ch != '_';
+    }
+
+    /**
+     * Returns the directory name corresponding to the specified node name.
+     * Generally, this is just the node name.  If the node name includes
+     * inappropriate characters (as per isDirChar) it is translated to Base64.
+     * with the underscore  character ('_', 0x5f) prepended.
+     */
+    private static String dirName(String nodeName) {
+        for (int i=0, n=nodeName.length(); i < n; i++)
+            if (!isDirChar(nodeName.charAt(i)))
+                return "_" + Base64.byteArrayToAltBase64(byteArray(nodeName));
+        return nodeName;
+    }
+
+    /**
+     * Translate a string into a byte array by translating each character
+     * into two bytes, high-byte first ("big-endian").
+     */
+    private static byte[] byteArray(String s) {
+        int len = s.length();
+        byte[] result = new byte[2*len];
+        for (int i=0, j=0; i<len; i++) {
+            char c = s.charAt(i);
+            result[j++] = (byte) (c>>8);
+            result[j++] = (byte) c;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the node name corresponding to the specified directory name.
+ * (Inverts the transformation of dirName(String).
+     */
+    private static String nodeName(String dirName) {
+        if (dirName.charAt(0) != '_')
+            return dirName;
+        byte a[] = Base64.altBase64ToByteArray(dirName.substring(1));
+        StringBuffer result = new StringBuffer(a.length/2);
+        for (int i = 0; i < a.length; ) {
+            int highByte = a[i++] & 0xff;
+            int lowByte =  a[i++] & 0xff;
+            result.append((char) ((highByte << 8) | lowByte));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Try to acquire the appropriate file lock (user or system).  If
+     * the initial attempt fails, several more attempts are made using
+     * an exponential backoff strategy.  If all attempts fail, this method
+     * returns false.
+     * @throws SecurityException if file access denied.
+     */
+    private boolean lockFile(boolean shared) throws SecurityException{
+        boolean usernode = isUserNode();
+        int[] result;
+        int errorCode = 0;
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        long sleepTime = INIT_SLEEP_TIME;
+        for (int i = 0; i < MAX_ATTEMPTS; i++) {
+            try {
+                  int perm = (usernode? USER_READ_WRITE: USER_RW_ALL_READ);
+                  result = lockFile0(lockFile.getCanonicalPath(), perm, shared);
+
+                  errorCode = result[ERROR_CODE];
+                  if (result[LOCK_HANDLE] != 0) {
+                     if (usernode) {
+                         userRootLockHandle = result[LOCK_HANDLE];
+                     } else {
+                         systemRootLockHandle = result[LOCK_HANDLE];
+                     }
+                     return true;
+                  }
+            } catch(IOException e) {
+//                // If at first, you don't succeed...
+            }
+
+            try {
+                Thread.sleep(sleepTime);
+            } catch(InterruptedException e) {
+                checkLockFile0ErrorCode(errorCode);
+                // Android-changed: don't lose the interrupt unless we throw.
+                Thread.currentThread().interrupt();
+                return false;
+            }
+            sleepTime *= 2;
+        }
+        checkLockFile0ErrorCode(errorCode);
+        return false;
+    }
+
+    /**
+     * Checks if unlockFile0() returned an error. Throws a SecurityException,
+     * if access denied. Logs a warning otherwise.
+     */
+    private void checkLockFile0ErrorCode (int errorCode)
+                                                      throws SecurityException {
+        if (errorCode == EACCES)
+            throw new SecurityException("Could not lock " +
+            (isUserNode()? "User prefs." : "System prefs.") +
+             " Lock file access denied.");
+        if (errorCode != EAGAIN)
+            getLogger().warning("Could not lock " +
+                             (isUserNode()? "User prefs. " : "System prefs.") +
+                             " Unix error code " + errorCode + ".");
+    }
+
+    /**
+     * Locks file using UNIX file locking.
+     * @param fileName Absolute file name of the lock file.
+     * @return Returns a lock handle, used to unlock the file.
+     */
+    private static native int[]
+            lockFile0(String fileName, int permission, boolean shared);
+
+    /**
+     * Unlocks file previously locked by lockFile0().
+     * @param lockHandle Handle to the file lock.
+     * @return Returns zero if OK, UNIX error code if failure.
+     */
+    private  static native int unlockFile0(int lockHandle);
+
+    /**
+     * Changes UNIX file permissions.
+     */
+    private static native int chmod(String fileName, int permission);
+
+    /**
+     * Initial time between lock attempts, in ms.  The time is doubled
+     * after each failing attempt (except the first).
+     */
+    private static int INIT_SLEEP_TIME = 50;
+
+    /**
+     * Maximum number of lock attempts.
+     */
+    private static int MAX_ATTEMPTS = 5;
+
+    /**
+     * Release the the appropriate file lock (user or system).
+     * @throws SecurityException if file access denied.
+     */
+    private void unlockFile() {
+        int result;
+        boolean usernode = isUserNode();
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        int lockHandle = ( usernode ? userRootLockHandle:systemRootLockHandle);
+        if (lockHandle == 0) {
+            getLogger().warning("Unlock: zero lockHandle for " +
+                           (usernode ? "user":"system") + " preferences.)");
+            return;
+        }
+        result = unlockFile0(lockHandle);
+        if (result != 0) {
+            getLogger().warning("Could not drop file-lock on " +
+            (isUserNode() ? "user" : "system") + " preferences." +
+            " Unix error code " + result + ".");
+            if (result == EACCES)
+                throw new SecurityException("Could not unlock" +
+                (isUserNode()? "User prefs." : "System prefs.") +
+                " Lock file access denied.");
+        }
+        if (isUserNode()) {
+            userRootLockHandle = 0;
+        } else {
+            systemRootLockHandle = 0;
+        }
+    }
+}
diff --git a/android-35/java/util/prefs/FileSystemPreferencesFactory.java b/android-35/java/util/prefs/FileSystemPreferencesFactory.java
new file mode 100644
index 0000000..bd1a723
--- /dev/null
+++ b/android-35/java/util/prefs/FileSystemPreferencesFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Factory for FileSystemPreferences.  This class allows FileSystemPreferences
+ * to be installed as the Preferences implementations via the
+ * java.util.prefs.PreferencesFactory system property.
+ *
+ * @author  Josh Bloch
+ * @see     FileSystemPreferences
+ * @see     Preferences
+ * @since   1.4
+ */
+
+class FileSystemPreferencesFactory implements PreferencesFactory {
+    public Preferences userRoot() {
+        return FileSystemPreferences.getUserRoot();
+    }
+
+    public Preferences systemRoot() {
+        return FileSystemPreferences.getSystemRoot();
+    }
+}
diff --git a/android-35/java/util/prefs/InvalidPreferencesFormatException.java b/android-35/java/util/prefs/InvalidPreferencesFormatException.java
new file mode 100644
index 0000000..3a5e817
--- /dev/null
+++ b/android-35/java/util/prefs/InvalidPreferencesFormatException.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of preferences, as per the {@link Preferences}
+ * specification.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public class InvalidPreferencesFormatException extends Exception {
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(Throwable cause) {
+        super(cause);
+    }
+
+   /**
+    * Constructs an InvalidPreferencesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPreferencesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * detail message and cause.
+     *
+     * @param  message   the detail message. The detail message is saved for
+     *         later retrieval by the {@link Throwable#getMessage()} method.
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    private static final long serialVersionUID = -791715184232119669L;
+}
diff --git a/android-35/java/util/prefs/NodeChangeEvent.java b/android-35/java/util/prefs/NodeChangeEvent.java
new file mode 100644
index 0000000..f108925
--- /dev/null
+++ b/android-35/java/util/prefs/NodeChangeEvent.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a child of that node has been added or removed.<p>
+ *
+ * Note, that although NodeChangeEvent inherits Serializable interface from
+ * java.util.EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeListener
+ * @see     PreferenceChangeEvent
+ * @since   1.4
+ * @serial  exclude
+ */
+
+public class NodeChangeEvent extends java.util.EventObject {
+    /**
+     * The node that was added or removed.
+     *
+     * @serial
+     */
+    private Preferences child;
+
+    /**
+     * Constructs a new <code>NodeChangeEvent</code> instance.
+     *
+     * @param parent  The parent of the node that was added or removed.
+     * @param child   The node that was added or removed.
+     */
+    public NodeChangeEvent(Preferences parent, Preferences child) {
+        super(parent);
+        this.child = child;
+    }
+
+    /**
+     * Returns the parent of the node that was added or removed.
+     *
+     * @return  The parent Preferences node whose child was added or removed
+     */
+    public Preferences getParent() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the node that was added or removed.
+     *
+     * @return  The node that was added or removed.
+     */
+    public Preferences getChild() {
+        return child;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 8068949086596572957L;
+}
diff --git a/android-35/java/util/prefs/NodeChangeListener.java b/android-35/java/util/prefs/NodeChangeListener.java
new file mode 100644
index 0000000..f343764
--- /dev/null
+++ b/android-35/java/util/prefs/NodeChangeListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference node change events.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeEvent
+ * @see     PreferenceChangeListener
+ * @since   1.4
+ */
+
+public interface NodeChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a child node is added.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childAdded(NodeChangeEvent evt);
+
+    /**
+     * This method gets called when a child node is removed.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childRemoved(NodeChangeEvent evt);
+}
diff --git a/android-35/java/util/prefs/PreferenceChangeEvent.java b/android-35/java/util/prefs/PreferenceChangeEvent.java
new file mode 100644
index 0000000..f7cf7b5
--- /dev/null
+++ b/android-35/java/util/prefs/PreferenceChangeEvent.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a preference has been added, removed or has had its value changed.<p>
+ *
+ * Note, that although PreferenceChangeEvent inherits Serializable interface
+ * from EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeListener
+ * @see NodeChangeEvent
+ * @since   1.4
+ * @serial exclude
+ */
+public class PreferenceChangeEvent extends java.util.EventObject {
+
+    /**
+     * Key of the preference that changed.
+     *
+     * @serial
+     */
+    private String key;
+
+    /**
+     * New value for preference, or <tt>null</tt> if it was removed.
+     *
+     * @serial
+     */
+    private String newValue;
+
+    /**
+     * Constructs a new <code>PreferenceChangeEvent</code> instance.
+     *
+     * @param node  The Preferences node that emitted the event.
+     * @param key  The key of the preference that was changed.
+     * @param newValue  The new value of the preference, or <tt>null</tt>
+     *                  if the preference is being removed.
+     */
+    public PreferenceChangeEvent(Preferences node, String key,
+                                 String newValue) {
+        super(node);
+        this.key = key;
+        this.newValue = newValue;
+    }
+
+    /**
+     * Returns the preference node that emitted the event.
+     *
+     * @return  The preference node that emitted the event.
+     */
+    public Preferences getNode() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the key of the preference that was changed.
+     *
+     * @return  The key of the preference that was changed.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the new value for the preference.
+     *
+     * @return  The new value for the preference, or <tt>null</tt> if the
+     *          preference was removed.
+     */
+    public String getNewValue() {
+        return newValue;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since PreferenceChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 793724513368024975L;
+}
diff --git a/android-35/java/util/prefs/PreferenceChangeListener.java b/android-35/java/util/prefs/PreferenceChangeListener.java
new file mode 100644
index 0000000..0fb96c5
--- /dev/null
+++ b/android-35/java/util/prefs/PreferenceChangeListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference change events.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeEvent
+ * @see NodeChangeListener
+ * @since   1.4
+ */
+@FunctionalInterface
+public interface PreferenceChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a preference is added, removed or when
+     * its value is changed.
+     * <p>
+     * @param evt A PreferenceChangeEvent object describing the event source
+     *          and the preference that has changed.
+     */
+    void preferenceChange(PreferenceChangeEvent evt);
+}
diff --git a/android-35/java/util/prefs/Preferences.java b/android-35/java/util/prefs/Preferences.java
new file mode 100644
index 0000000..c643fc2
--- /dev/null
+++ b/android-35/java/util/prefs/Preferences.java
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.RuntimePermission;
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * A node in a hierarchical collection of preference data.  This class
+ * allows applications to store and retrieve user and system
+ * preference and configuration data.  This data is stored
+ * persistently in an implementation-dependent backing store.  Typical
+ * implementations include flat files, OS-specific registries,
+ * directory servers and SQL databases.  The user of this class needn't
+ * be concerned with details of the backing store.
+ *
+ * <p>There are two separate trees of preference nodes, one for user
+ * preferences and one for system preferences.  Each user has a separate user
+ * preference tree, and all users in a given system share the same system
+ * preference tree.  The precise description of "user" and "system" will vary
+ * from implementation to implementation.  Typical information stored in the
+ * user preference tree might include font choice, color choice, or preferred
+ * window location and size for a particular application.  Typical information
+ * stored in the system preference tree might include installation
+ * configuration data for an application.
+ *
+ * <p>Nodes in a preference tree are named in a similar fashion to
+ * directories in a hierarchical file system.   Every node in a preference
+ * tree has a <i>node name</i> (which is not necessarily unique),
+ * a unique <i>absolute path name</i>, and a path name <i>relative</i> to each
+ * ancestor including itself.
+ *
+ * <p>The root node has a node name of the empty string ("").  Every other
+ * node has an arbitrary node name, specified at the time it is created.  The
+ * only restrictions on this name are that it cannot be the empty string, and
+ * it cannot contain the slash character ('/').
+ *
+ * <p>The root node has an absolute path name of <tt>"/"</tt>.  Children of
+ * the root node have absolute path names of <tt>"/" + </tt><i>&lt;node
+ * name&gt;</i>.  All other nodes have absolute path names of <i>&lt;parent's
+ * absolute path name&gt;</i><tt> + "/" + </tt><i>&lt;node name&gt;</i>.
+ * Note that all absolute path names begin with the slash character.
+ *
+ * <p>A node <i>n</i>'s path name relative to its ancestor <i>a</i>
+ * is simply the string that must be appended to <i>a</i>'s absolute path name
+ * in order to form <i>n</i>'s absolute path name, with the initial slash
+ * character (if present) removed.  Note that:
+ * <ul>
+ * <li>No relative path names begin with the slash character.
+ * <li>Every node's path name relative to itself is the empty string.
+ * <li>Every node's path name relative to its parent is its node name (except
+ * for the root node, which does not have a parent).
+ * <li>Every node's path name relative to the root is its absolute path name
+ * with the initial slash character removed.
+ * </ul>
+ *
+ * <p>Note finally that:
+ * <ul>
+ * <li>No path name contains multiple consecutive slash characters.
+ * <li>No path name with the exception of the root's absolute path name
+ * ends in the slash character.
+ * <li>Any string that conforms to these two rules is a valid path name.
+ * </ul>
+ *
+ * <p>All of the methods that modify preferences data are permitted to operate
+ * asynchronously; they may return immediately, and changes will eventually
+ * propagate to the persistent backing store with an implementation-dependent
+ * delay.  The <tt>flush</tt> method may be used to synchronously force
+ * updates to the backing store.  Normal termination of the Java Virtual
+ * Machine will <i>not</i> result in the loss of pending updates -- an explicit
+ * <tt>flush</tt> invocation is <i>not</i> required upon termination to ensure
+ * that pending updates are made persistent.
+ *
+ * <p>All of the methods that read preferences from a <tt>Preferences</tt>
+ * object require the invoker to provide a default value.  The default value is
+ * returned if no value has been previously set <i>or if the backing store is
+ * unavailable</i>.  The intent is to allow applications to operate, albeit
+ * with slightly degraded functionality, even if the backing store becomes
+ * unavailable.  Several methods, like <tt>flush</tt>, have semantics that
+ * prevent them from operating if the backing store is unavailable.  Ordinary
+ * applications should have no need to invoke any of these methods, which can
+ * be identified by the fact that they are declared to throw {@link
+ * BackingStoreException}.
+ *
+ * <p>The methods in this class may be invoked concurrently by multiple threads
+ * in a single JVM without the need for external synchronization, and the
+ * results will be equivalent to some serial execution.  If this class is used
+ * concurrently <i>by multiple JVMs</i> that store their preference data in
+ * the same backing store, the data store will not be corrupted, but no
+ * other guarantees are made concerning the consistency of the preference
+ * data.
+ *
+ * <p>This class contains an export/import facility, allowing preferences
+ * to be "exported" to an XML document, and XML documents representing
+ * preferences to be "imported" back into the system.  This facility
+ * may be used to back up all or part of a preference tree, and
+ * subsequently restore from the backup.
+ *
+ * <p>The XML document has the following DOCTYPE declaration:
+ * <pre>{@code
+ * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+ * }</pre>
+ * Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is
+ * <i>not</i> accessed when exporting or importing preferences; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>{@code
+ *    <?xml version="1.0" encoding="UTF-8"?>
+ *
+ *    <!-- DTD for a Preferences tree. -->
+ *
+ *    <!-- The preferences element is at the root of an XML document
+ *         representing a Preferences tree. -->
+ *    <!ELEMENT preferences (root)>
+ *
+ *    <!-- The preferences element contains an optional version attribute,
+ *          which specifies version of DTD. -->
+ *    <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
+ *
+ *    <!-- The root element has a map representing the root's preferences
+ *         (if any), and one node for each child of the root (if any). -->
+ *    <!ELEMENT root (map, node*) >
+ *
+ *    <!-- Additionally, the root contains a type attribute, which
+ *         specifies whether it's the system or user root. -->
+ *    <!ATTLIST root
+ *              type (system|user) #REQUIRED >
+ *
+ *    <!-- Each node has a map representing its preferences (if any),
+ *         and one node for each child (if any). -->
+ *    <!ELEMENT node (map, node*) >
+ *
+ *    <!-- Additionally, each node has a name attribute -->
+ *    <!ATTLIST node
+ *              name CDATA #REQUIRED >
+ *
+ *    <!-- A map represents the preferences stored at a node (if any). -->
+ *    <!ELEMENT map (entry*) >
+ *
+ *    <!-- An entry represents a single preference, which is simply
+ *          a key-value pair. -->
+ *    <!ELEMENT entry EMPTY >
+ *    <!ATTLIST entry
+ *              key   CDATA #REQUIRED
+ *              value CDATA #REQUIRED >
+ * }</pre>
+ *
+ * Every <tt>Preferences</tt> implementation must have an associated {@link
+ * PreferencesFactory} implementation.  Every Java(TM) SE implementation must provide
+ * some means of specifying which <tt>PreferencesFactory</tt> implementation
+ * is used to generate the root preferences nodes.  This allows the
+ * administrator to replace the default preferences implementation with an
+ * alternative implementation.
+ *
+ * <p>Implementation note: In Sun's JRE, the <tt>PreferencesFactory</tt>
+ * implementation is located as follows:
+ *
+ * <ol>
+ *
+ * <li><p>If the system property
+ * <tt>java.util.prefs.PreferencesFactory</tt> is defined, then it is
+ * taken to be the fully-qualified name of a class implementing the
+ * <tt>PreferencesFactory</tt> interface.  The class is loaded and
+ * instantiated; if this process fails then an unspecified error is
+ * thrown.</p></li>
+ *
+ * <li><p> If a <tt>PreferencesFactory</tt> implementation class file
+ * has been installed in a jar file that is visible to the
+ * {@link java.lang.ClassLoader#getSystemClassLoader system class loader},
+ * and that jar file contains a provider-configuration file named
+ * <tt>java.util.prefs.PreferencesFactory</tt> in the resource
+ * directory <tt>META-INF/services</tt>, then the first class name
+ * specified in that file is taken.  If more than one such jar file is
+ * provided, the first one found will be used.  The class is loaded
+ * and instantiated; if this process fails then an unspecified error
+ * is thrown.  </p></li>
+ *
+ * <li><p>Finally, if neither the above-mentioned system property nor
+ * an extension jar file is provided, then the system-wide default
+ * <tt>PreferencesFactory</tt> implementation for the underlying
+ * platform is loaded and instantiated.</p></li>
+ *
+ * </ol>
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public abstract class Preferences {
+
+    // Android-changed: Allow Preferences.factory to be set by tests.
+    // private static final PreferencesFactory factory = factory();
+    private static PreferencesFactory factory = factory();
+
+    // BEGIN Android-changed: Logic for constructing the default Preferences factory.
+    /*
+    private static PreferencesFactory factory() {
+        // 1. Try user-specified system property
+        String factoryName = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return System.getProperty(
+                        "java.util.prefs.PreferencesFactory");}});
+        if (factoryName != null) {
+            // FIXME: This code should be run in a doPrivileged and
+            // not use the context classloader, to avoid being
+            // dependent on the invoking thread.
+            // Checking AllPermission also seems wrong.
+            try {
+                return (PreferencesFactory)
+                    Class.forName(factoryName, false,
+                                  ClassLoader.getSystemClassLoader())
+                    .newInstance();
+            } catch (Exception ex) {
+                try {
+                    // workaround for javaws, plugin,
+                    // load factory class using non-system classloader
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        sm.checkPermission(new java.security.AllPermission());
+                    }
+                    return (PreferencesFactory)
+                        Class.forName(factoryName, false,
+                                      Thread.currentThread()
+                                      .getContextClassLoader())
+                        .newInstance();
+                } catch (Exception e) {
+                    throw new InternalError(
+                        "Can't instantiate Preferences factory "
+                        + factoryName, e);
+                }
+            }
+        }
+
+        return AccessController.doPrivileged(
+            new PrivilegedAction<PreferencesFactory>() {
+                public PreferencesFactory run() {
+                    return factory1();}});
+    }
+
+    private static PreferencesFactory factory1() {
+        // 2. Try service provider interface
+        Iterator<PreferencesFactory> itr = ServiceLoader
+            .load(PreferencesFactory.class, ClassLoader.getSystemClassLoader())
+            .iterator();
+
+        // choose first provider instance
+        while (itr.hasNext()) {
+            try {
+                return itr.next();
+            } catch (ServiceConfigurationError sce) {
+                if (sce.getCause() instanceof SecurityException) {
+                    // Ignore the security exception, try the next provider
+                    continue;
+                }
+                throw sce;
+            }
+        }
+
+        // 3. Use platform-specific system-wide default
+        String osName = System.getProperty("os.name");
+        String platformFactory;
+        if (osName.startsWith("Windows")) {
+            platformFactory = "java.util.prefs.WindowsPreferencesFactory";
+        } else if (osName.contains("OS X")) {
+            platformFactory = "java.util.prefs.MacOSXPreferencesFactory";
+        } else {
+            platformFactory = "java.util.prefs.FileSystemPreferencesFactory";
+        }
+        try {
+            return (PreferencesFactory)
+                Class.forName(platformFactory, false,
+                              Preferences.class.getClassLoader()).newInstance();
+        } catch (Exception e) {
+            throw new InternalError(
+                "Can't instantiate platform default Preferences factory "
+                + platformFactory, e);
+        }
+    }
+    */
+    private static PreferencesFactory factory() {
+        // Try the system property first...
+        PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class);
+        if (result != null) {
+            return result;
+        }
+        // Then use ServiceLoader for META-INF/services/...
+        for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) {
+            return impl;
+        }
+        // Finally return a default...
+        return new FileSystemPreferencesFactory();
+    }
+    // END Android-changed: Logic for constructing the default Preferences factory.
+
+    // BEGIN Android-added: Allow Preferences.factory to be set by tests.
+    /** @hide for testing only. */
+    public static PreferencesFactory setPreferencesFactory(PreferencesFactory pf) {
+        PreferencesFactory previous = factory;
+        factory = pf;
+        return previous;
+    }
+    // END Android-added: Allow Preferences.factory to be set by tests.
+
+    /**
+     * Maximum length of string allowed as a key (80 characters).
+     */
+    public static final int MAX_KEY_LENGTH = 80;
+
+    /**
+     * Maximum length of string allowed as a value (8192 characters).
+     */
+    public static final int MAX_VALUE_LENGTH = 8*1024;
+
+    /**
+     * Maximum length of a node name (80 characters).
+     */
+    public static final int MAX_NAME_LENGTH = 80;
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the calling user's preference tree
+     * that is associated (by convention) with the specified class's package.
+     * The convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *    static Preferences prefs = Preferences.userNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a user preference node is desired.
+     * @return the user preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userNodeForPackage(Class<?> c) {
+        return userRoot().node(nodeName(c));
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the system preference tree that is
+     * associated (by convention) with the specified class's package.  The
+     * convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *  static Preferences prefs = Preferences.systemNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a system preference node is desired.
+     * @return the system preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemNodeForPackage(Class<?> c) {
+        return systemRoot().node(nodeName(c));
+    }
+
+    /**
+     * Returns the absolute path name of the node corresponding to the package
+     * of the specified object.
+     *
+     * @throws IllegalArgumentException if the package has node preferences
+     *         node associated with it.
+     */
+    private static String nodeName(Class<?> c) {
+        if (c.isArray())
+            throw new IllegalArgumentException(
+                "Arrays have no associated preferences node.");
+        String className = c.getName();
+        int pkgEndIndex = className.lastIndexOf('.');
+        if (pkgEndIndex < 0)
+            return "/<unnamed>";
+        String packageName = className.substring(0, pkgEndIndex);
+        return "/" + packageName.replace('.', '/');
+    }
+
+    /**
+     * This permission object represents the permission required to get
+     * access to the user or system root (which in turn allows for all
+     * other operations).
+     */
+    private static Permission prefsPerm = new RuntimePermission("preferences");
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the calling user.
+     *
+     * @return the root preference node for the calling user.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.userRoot();
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the system.
+     *
+     * @return the root preference node for the system.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.systemRoot();
+    }
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected Preferences() {
+    }
+
+    /**
+     * Associates the specified value with the specified key in this
+     * preference node.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void put(String key, String value);
+
+    /**
+     * Returns the value associated with the specified key in this preference
+     * node.  Returns the specified default if there is no value associated
+     * with the key, or the backing store is inaccessible.
+     *
+     * <p>Some implementations may store default values in their backing
+     * stores.  If there is no value associated with the specified key
+     * but there is such a <i>stored default</i>, it is returned in
+     * preference to the specified default.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>, or the backing
+     *         store is inaccessible.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public abstract String get(String key, String def);
+
+    /**
+     * Removes the value associated with the specified key in this preference
+     * node, if any.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and there is
+     * such a default for the specified preference, the stored default will be
+     * "exposed" by this call, in the sense that it will be returned
+     * by a succeeding call to <tt>get</tt>.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void remove(String key);
+
+    /**
+     * Removes all of the preferences (key-value associations) in this
+     * preference node.  This call has no effect on any descendants
+     * of this node.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and this
+     * node in the preferences hierarchy contains any such defaults,
+     * the stored defaults will be "exposed" by this call, in the sense that
+     * they will be returned by succeeding calls to <tt>get</tt>.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNode()
+     */
+    public abstract void clear() throws BackingStoreException;
+
+    /**
+     * Associates a string representing the specified int value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the int value were passed to
+     * {@link Integer#toString(int)}.  This method is intended for use in
+     * conjunction with {@link #getInt}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getInt(String,int)
+     */
+    public abstract void putInt(String key, int value);
+
+    /**
+     * Returns the int value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * an integer as by {@link Integer#parseInt(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Integer.parseInt(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putInt}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to an int
+     * with <tt>Integer.parseInt</tt>, this int is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int,
+     *        or the backing store is inaccessible.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putInt(String,int)
+     * @see #get(String,String)
+     */
+    public abstract int getInt(String key, int def);
+
+    /**
+     * Associates a string representing the specified long value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the long value were passed to
+     * {@link Long#toString(long)}.  This method is intended for use in
+     * conjunction with {@link #getLong}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getLong(String,long)
+     */
+    public abstract void putLong(String key, long value);
+
+    /**
+     * Returns the long value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * a long as by {@link Long#parseLong(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Long.parseLong(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putLong}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a long
+     * with <tt>Long.parseLong</tt>, this long is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long,
+     *        or the backing store is inaccessible.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putLong(String,long)
+     * @see #get(String,String)
+     */
+    public abstract long getLong(String key, long def);
+
+    /**
+     * Associates a string representing the specified boolean value with the
+     * specified key in this preference node.  The associated string is
+     * <tt>"true"</tt> if the value is true, and <tt>"false"</tt> if it is
+     * false.  This method is intended for use in conjunction with
+     * {@link #getBoolean}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getBoolean(String,boolean)
+     * @see #get(String,String)
+     */
+    public abstract void putBoolean(String key, boolean value);
+
+    /**
+     * Returns the boolean value represented by the string associated with the
+     * specified key in this preference node.  Valid strings
+     * are <tt>"true"</tt>, which represents true, and <tt>"false"</tt>, which
+     * represents false.  Case is ignored, so, for example, <tt>"TRUE"</tt>
+     * and <tt>"False"</tt> are also valid.  This method is intended for use in
+     * conjunction with {@link #putBoolean}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is something other than <tt>"true"</tt> or
+     * <tt>"false"</tt>, ignoring case.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is something other than
+     * <tt>"true"</tt> or <tt>"false"</tt>, ignoring case, in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean,
+     *        or the backing store is inaccessible.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #get(String,String)
+     * @see #putBoolean(String,boolean)
+     */
+    public abstract boolean getBoolean(String key, boolean def);
+
+    /**
+     * Associates a string representing the specified float value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the float value were passed to
+     * {@link Float#toString(float)}.  This method is intended for use in
+     * conjunction with {@link #getFloat}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getFloat(String,float)
+     */
+    public abstract void putFloat(String key, float value);
+
+    /**
+     * Returns the float value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Float#parseFloat(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Float.parseFloat(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putFloat}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a float
+     * with <tt>Float.parseFloat</tt>, this float is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float,
+     *        or the backing store is inaccessible.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putFloat(String,float)
+     * @see #get(String,String)
+     */
+    public abstract float getFloat(String key, float def);
+
+    /**
+     * Associates a string representing the specified double value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the double value were passed to
+     * {@link Double#toString(double)}.  This method is intended for use in
+     * conjunction with {@link #getDouble}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getDouble(String,double)
+     */
+    public abstract void putDouble(String key, double value);
+
+    /**
+     * Returns the double value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Double#parseDouble(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Double.parseDouble(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putDouble}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a double
+     * with <tt>Double.parseDouble</tt>, this double is returned in preference
+     * to the specified default.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double,
+     *        or the backing store is inaccessible.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putDouble(String,double)
+     * @see #get(String,String)
+     */
+    public abstract double getDouble(String key, double def);
+
+    /**
+     * Associates a string representing the specified byte array with the
+     * specified key in this preference node.  The associated string is
+     * the <i>Base64</i> encoding of the byte array, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string will consist solely of characters
+     * from the <i>Base64 Alphabet</i>; it will not contain any newline
+     * characters.  Note that the maximum length of the byte array is limited
+     * to three quarters of <tt>MAX_VALUE_LENGTH</tt> so that the length
+     * of the Base64 encoded String does not exceed <tt>MAX_VALUE_LENGTH</tt>.
+     * This method is intended for use in conjunction with
+     * {@link #getByteArray}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getByteArray(String,byte[])
+     * @see #get(String,String)
+     */
+    public abstract void putByteArray(String key, byte[] value);
+
+    /**
+     * Returns the byte array value represented by the string associated with
+     * the specified key in this preference node.  Valid strings are
+     * <i>Base64</i> encoded binary data, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string must consist solely of characters
+     * from the <i>Base64 Alphabet</i>; no newline characters or
+     * extraneous characters are permitted.  This method is intended for use
+     * in conjunction with {@link #putByteArray}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is not a valid Base64 encoded byte array
+     * (as defined above).
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is not a valid Base64
+     * encoded byte array (as defined above), in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array,
+     *        or the backing store is inaccessible.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     * @see #get(String,String)
+     * @see #putByteArray(String,byte[])
+     */
+    public abstract byte[] getByteArray(String key, byte[] def);
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and there
+     * are any such defaults at this node that have not been overridden,
+     * by explicit preferences, the defaults are returned in the array in
+     * addition to any explicit preferences.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] keys() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node, relative to
+     * this node.  (The returned array will be of size zero if this node has
+     * no children.)
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] childrenNames() throws BackingStoreException;
+
+    /**
+     * Returns the parent of this preference node, or <tt>null</tt> if this is
+     * the root.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract Preferences parent();
+
+    /**
+     * Returns the named preference node in the same tree as this node,
+     * creating it and any of its ancestors if they do not already exist.
+     * Accepts a relative or absolute path name.  Relative path names
+     * (which do not begin with the slash character <tt>('/')</tt>) are
+     * interpreted relative to this preference node.
+     *
+     * <p>If the returned node did not exist prior to this call, this node and
+     * any ancestors that were created by this call are not guaranteed
+     * to become permanent until the <tt>flush</tt> method is called on
+     * the returned node (or one of its ancestors or descendants).
+     *
+     * @param pathName the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public abstract Preferences node(String pathName);
+
+    /**
+     * Returns true if the named preference node exists in the same tree
+     * as this node.  Relative path names (which do not begin with the slash
+     * character <tt>('/')</tt>) are interpreted relative to this preference
+     * node.
+     *
+     * <p>If this node (or an ancestor) has already been removed with the
+     * {@link #removeNode()} method, it <i>is</i> legal to invoke this method,
+     * but only with the path name <tt>""</tt>; the invocation will return
+     * <tt>false</tt>.  Thus, the idiom <tt>p.nodeExists("")</tt> may be
+     * used to test whether <tt>p</tt> has been removed.
+     *
+     * @param pathName the path name of the node whose existence
+     *        is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathName</tt> is not the empty string (<tt>""</tt>).
+     */
+    public abstract boolean nodeExists(String pathName)
+        throws BackingStoreException;
+
+    /**
+     * Removes this preference node and all of its descendants, invalidating
+     * any preferences contained in the removed nodes.  Once a node has been
+     * removed, attempting any method other than {@link #name()},
+     * {@link #absolutePath()}, {@link #isUserNode()}, {@link #flush()} or
+     * {@link #node(String) nodeExists("")} on the corresponding
+     * <tt>Preferences</tt> instance will fail with an
+     * <tt>IllegalStateException</tt>.  (The methods defined on {@link Object}
+     * can still be invoked on a node after it has been removed; they will not
+     * throw <tt>IllegalStateException</tt>.)
+     *
+     * <p>The removal is not guaranteed to be persistent until the
+     * <tt>flush</tt> method is called on this node (or an ancestor).
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, removing a
+     * node exposes any stored defaults at or below this node.  Thus, a
+     * subsequent call to <tt>nodeExists</tt> on this node's path name may
+     * return <tt>true</tt>, and a subsequent call to <tt>node</tt> on this
+     * path name may return a (different) <tt>Preferences</tt> instance
+     * representing a non-empty collection of preferences and/or children.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @see #flush()
+     */
+    public abstract void removeNode() throws BackingStoreException;
+
+    /**
+     * Returns this preference node's name, relative to its parent.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public abstract String name();
+
+    /**
+     * Returns this preference node's absolute path name.
+     *
+     * @return this preference node's absolute path name.
+     */
+    public abstract String absolutePath();
+
+    /**
+     * Returns <tt>true</tt> if this preference node is in the user
+     * preference tree, <tt>false</tt> if it's in the system preference tree.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public abstract boolean isUserNode();
+
+    /**
+     * Returns a string representation of this preferences node,
+     * as if computed by the expression:<tt>(this.isUserNode() ? "User" :
+     * "System") + " Preference Node: " + this.absolutePath()</tt>.
+     */
+    public abstract String toString();
+
+    /**
+     * Forces any changes in the contents of this preference node and its
+     * descendants to the persistent store.  Once this method returns
+     * successfully, it is safe to assume that all changes made in the
+     * subtree rooted at this node prior to the method invocation have become
+     * permanent.
+     *
+     * <p>Implementations are free to flush changes into the persistent store
+     * at any time.  They do not need to wait for this method to be called.
+     *
+     * <p>When a flush occurs on a newly created node, it is made persistent,
+     * as are any ancestors (and descendants) that have yet to be made
+     * persistent.  Note however that any preference value changes in
+     * ancestors are <i>not</i> guaranteed to be made persistent.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see    #sync()
+     */
+    public abstract void flush() throws BackingStoreException;
+
+    /**
+     * Ensures that future reads from this preference node and its
+     * descendants reflect any changes that were committed to the persistent
+     * store (from any VM) prior to the <tt>sync</tt> invocation.  As a
+     * side-effect, forces any changes in the contents of this preference node
+     * and its descendants to the persistent store, as if the <tt>flush</tt>
+     * method had been invoked on this node.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #flush()
+     */
+    public abstract void sync() throws BackingStoreException;
+
+    /**
+     * Registers the specified listener to receive <i>preference change
+     * events</i> for this preference node.  A preference change event is
+     * generated when a preference is added to this node, removed from this
+     * node, or when the value associated with a preference is changed.
+     * (Preference change events are <i>not</i> generated by the {@link
+     * #removeNode()} method, which generates a <i>node change event</i>.
+     * Preference change events <i>are</i> generated by the <tt>clear</tt>
+     * method.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have been made persistent.  Events are not generated
+     * when preferences are modified in descendants of this node; a caller
+     * desiring such events must register with each descendant.
+     *
+     * @param pcl The preference change listener to add.
+     * @throws NullPointerException if <tt>pcl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removePreferenceChangeListener(PreferenceChangeListener)
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void addPreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Removes the specified preference change listener, so it no longer
+     * receives preference change events.
+     *
+     * @param pcl The preference change listener to remove.
+     * @throws IllegalArgumentException if <tt>pcl</tt> was not a registered
+     *         preference change listener on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void removePreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Registers the specified listener to receive <i>node change events</i>
+     * for this node.  A node change event is generated when a child node is
+     * added to or removed from this node.  (A single {@link #removeNode()}
+     * invocation results in multiple <i>node change events</i>, one for every
+     * node in the subtree rooted at the removed node.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have become permanent.  Events are not generated
+     * when indirect descendants of this node are added or removed; a
+     * caller desiring such events must register with each descendant.
+     *
+     * <p>Few guarantees can be made regarding node creation.  Because nodes
+     * are created implicitly upon access, it may not be feasible for an
+     * implementation to determine whether a child node existed in the backing
+     * store prior to access (for example, because the backing store is
+     * unreachable or cached information is out of date).  Under these
+     * circumstances, implementations are neither required to generate node
+     * change events nor prohibited from doing so.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to add.
+     * @throws NullPointerException if <tt>ncl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNodeChangeListener(NodeChangeListener)
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void addNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Removes the specified <tt>NodeChangeListener</tt>, so it no longer
+     * receives change events.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to remove.
+     * @throws IllegalArgumentException if <tt>ncl</tt> was not a registered
+     *         <tt>NodeChangeListener</tt> on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void removeNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Emits on the specified output stream an XML document representing all
+     * of the preferences contained in this node (but not its descendants).
+     * This XML document is, in effect, an offline backup of the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * at this node are modified concurrently with an invocation of this
+     * method, the exported preferences comprise a "fuzzy snapshot" of the
+     * preferences contained in the node; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @see    #importPreferences(InputStream)
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void exportNode(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Emits an XML document representing all of the preferences contained
+     * in this node and all of its descendants.  This XML document is, in
+     * effect, an offline backup of the subtree rooted at the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * or nodes in the subtree rooted at this node are modified concurrently
+     * with an invocation of this method, the exported preferences comprise a
+     * "fuzzy snapshot" of the subtree; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #importPreferences(InputStream)
+     * @see    #exportNode(OutputStream)
+     */
+    public abstract void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Imports all of the preferences represented by the XML document on the
+     * specified input stream.  The document may represent user preferences or
+     * system preferences.  If it represents user preferences, the preferences
+     * will be imported into the calling user's preference tree (even if they
+     * originally came from a different user's preference tree).  If any of
+     * the preferences described by the document inhabit preference nodes that
+     * do not exist, the nodes will be created.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * (This method is designed for use in conjunction with
+     * {@link #exportNode(OutputStream)} and
+     * {@link #exportSubtree(OutputStream)}.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  The method behaves
+     * as if implemented on top of the other public methods in this class,
+     * notably {@link #node(String)} and {@link #put(String, String)}.
+     *
+     * @param is the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        XmlSupport.importPreferences(is);
+    }
+}
diff --git a/android-35/java/util/prefs/PreferencesFactory.java b/android-35/java/util/prefs/PreferencesFactory.java
new file mode 100644
index 0000000..d7341e6
--- /dev/null
+++ b/android-35/java/util/prefs/PreferencesFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+
+/**
+ * A factory object that generates Preferences objects.  Providers of
+ * new {@link Preferences} implementations should provide corresponding
+ * <tt>PreferencesFactory</tt> implementations so that the new
+ * <tt>Preferences</tt> implementation can be installed in place of the
+ * platform-specific default implementation.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.</strong>
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public interface PreferencesFactory {
+    /**
+     * Returns the system root preference node.  (Multiple calls on this
+     * method will return the same object reference.)
+     * @return the system root preference node
+     */
+    Preferences systemRoot();
+
+    /**
+     * Returns the user root preference node corresponding to the calling
+     * user.  In a server, the returned value will typically depend on
+     * some implicit client-context.
+     * @return the user root preference node corresponding to the calling
+     * user
+     */
+    Preferences userRoot();
+}
diff --git a/android-35/java/util/prefs/XmlSupport.java b/android-35/java/util/prefs/XmlSupport.java
new file mode 100644
index 0000000..a90ff19
--- /dev/null
+++ b/android-35/java/util/prefs/XmlSupport.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+/**
+ * XML Support for java.util.prefs. Methods to import and export preference
+ * nodes and subtrees.
+ *
+ * @author  Josh Bloch and Mark Reinhold
+ * @see     Preferences
+ * @since   1.4
+ */
+class XmlSupport {
+    // The required DTD URI for exported preferences
+    private static final String PREFS_DTD_URI =
+        "http://java.sun.com/dtd/preferences.dtd";
+
+    // The actual DTD corresponding to the URI
+    private static final String PREFS_DTD =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+
+        "<!-- DTD for preferences -->"               +
+
+        "<!ELEMENT preferences (root) >"             +
+        "<!ATTLIST preferences"                      +
+        " EXTERNAL_XML_VERSION CDATA \"0.0\"  >"     +
+
+        "<!ELEMENT root (map, node*) >"              +
+        "<!ATTLIST root"                             +
+        "          type (system|user) #REQUIRED >"   +
+
+        "<!ELEMENT node (map, node*) >"              +
+        "<!ATTLIST node"                             +
+        "          name CDATA #REQUIRED >"           +
+
+        "<!ELEMENT map (entry*) >"                   +
+        "<!ATTLIST map"                              +
+        "  MAP_XML_VERSION CDATA \"0.0\"  >"         +
+        "<!ELEMENT entry EMPTY >"                    +
+        "<!ATTLIST entry"                            +
+        "          key CDATA #REQUIRED"              +
+        "          value CDATA #REQUIRED >"          ;
+    /**
+     * Version number for the format exported preferences files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    /*
+     * Version number for the internal map files.
+     */
+    private static final String MAP_XML_VERSION = "1.0";
+
+    /**
+     * Export the specified preferences node and, if subTree is true, all
+     * subnodes, to the specified output stream.  Preferences are exported as
+     * an XML document conforming to the definition in the Preferences spec.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link Preferences#removeNode()} method.
+     */
+    static void export(OutputStream os, final Preferences p, boolean subTree)
+        throws IOException, BackingStoreException {
+        if (((AbstractPreferences)p).isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        Document doc = createPrefsDoc("preferences");
+        Element preferences =  doc.getDocumentElement() ;
+        preferences.setAttribute("EXTERNAL_XML_VERSION", EXTERNAL_XML_VERSION);
+        Element xmlRoot =  (Element)
+        preferences.appendChild(doc.createElement("root"));
+        xmlRoot.setAttribute("type", (p.isUserNode() ? "user" : "system"));
+
+        // Get bottom-up list of nodes from p to root, excluding root
+        List<Preferences> ancestors = new ArrayList<>();
+
+        for (Preferences kid = p, dad = kid.parent(); dad != null;
+                                   kid = dad, dad = kid.parent()) {
+            ancestors.add(kid);
+        }
+        Element e = xmlRoot;
+        for (int i=ancestors.size()-1; i >= 0; i--) {
+            e.appendChild(doc.createElement("map"));
+            e = (Element) e.appendChild(doc.createElement("node"));
+            e.setAttribute("name", ancestors.get(i).name());
+        }
+        putPreferencesInXml(e, doc, p, subTree);
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Put the preferences in the specified Preferences node into the
+     * specified XML element which is assumed to represent a node
+     * in the specified XML document which is assumed to conform to
+     * PREFS_DTD.  If subTree is true, create children of the specified
+     * XML node conforming to all of the children of the specified
+     * Preferences node and recurse.
+     *
+     * @throws BackingStoreException if it is not possible to read
+     *         the preferences or children out of the specified
+     *         preferences node.
+     */
+    private static void putPreferencesInXml(Element elt, Document doc,
+               Preferences prefs, boolean subTree) throws BackingStoreException
+    {
+        Preferences[] kidsCopy = null;
+        String[] kidNames = null;
+
+        // Node is locked to export its contents and get a
+        // copy of children, then lock is released,
+        // and, if subTree = true, recursive calls are made on children
+        synchronized (((AbstractPreferences)prefs).lock) {
+            // Check if this node was concurrently removed. If yes
+            // remove it from XML Document and return.
+            if (((AbstractPreferences)prefs).isRemoved()) {
+                elt.getParentNode().removeChild(elt);
+                return;
+            }
+            // Put map in xml element
+            String[] keys = prefs.keys();
+            Element map = (Element) elt.appendChild(doc.createElement("map"));
+            for (int i=0; i<keys.length; i++) {
+                Element entry = (Element)
+                    map.appendChild(doc.createElement("entry"));
+                entry.setAttribute("key", keys[i]);
+                // NEXT STATEMENT THROWS NULL PTR EXC INSTEAD OF ASSERT FAIL
+                entry.setAttribute("value", prefs.get(keys[i], null));
+            }
+            // Recurse if appropriate
+            if (subTree) {
+                /* Get a copy of kids while lock is held */
+                kidNames = prefs.childrenNames();
+                kidsCopy = new Preferences[kidNames.length];
+                for (int i = 0; i <  kidNames.length; i++)
+                    kidsCopy[i] = prefs.node(kidNames[i]);
+            }
+            // release lock
+        }
+
+        if (subTree) {
+            for (int i=0; i < kidNames.length; i++) {
+                Element xmlKid = (Element)
+                    elt.appendChild(doc.createElement("node"));
+                xmlKid.setAttribute("name", kidNames[i]);
+                putPreferencesInXml(xmlKid, doc, kidsCopy[i], subTree);
+            }
+        }
+    }
+
+    /**
+     * Import preferences from the specified input stream, which is assumed
+     * to contain an XML document in the format described in the Preferences
+     * spec.
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            String xmlVersion =
+                doc.getDocumentElement().getAttribute("EXTERNAL_XML_VERSION");
+            if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Exported preferences file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            // BEGIN Android-changed: Filter out non-Element nodes.
+            // Use a selector to skip over CDATA / DATA elements.
+            // The selector is specific to children with tag name "root";
+            // export() always creates exactly one such child.
+            // Element xmlRoot = (Element) doc.getDocumentElement().
+            //                                    getChildNodes().item(0);
+            Element xmlRoot = (Element) doc.getDocumentElement();
+
+            NodeList elements = xmlRoot.getElementsByTagName("root");
+            if (elements == null || elements.getLength() != 1) {
+                throw new InvalidPreferencesFormatException("invalid root node");
+            }
+
+            xmlRoot = (Element) elements.item(0);
+            // END Android-changed: Filter out non-Element nodes.
+            Preferences prefsRoot =
+                (xmlRoot.getAttribute("type").equals("user") ?
+                            Preferences.userRoot() : Preferences.systemRoot());
+            ImportSubtree(prefsRoot, xmlRoot);
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    /**
+     * Create a new prefs XML document.
+     */
+    private static Document createPrefsDoc( String qname ) {
+        try {
+            DOMImplementation di = DocumentBuilderFactory.newInstance().
+                newDocumentBuilder().getDOMImplementation();
+            DocumentType dt = di.createDocumentType(qname, null, PREFS_DTD_URI);
+            return di.createDocument(null, qname, dt);
+        } catch(ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Load an XML document from specified input stream, which must
+     * have the requisite DTD URI.
+     */
+    private static Document loadPrefsDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: No validating builder implementation.
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            return db.parse(new InputSource(in));
+        } catch (ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Write XML document to the specified output stream.
+     */
+    private static final void writeDoc(Document doc, OutputStream out)
+        throws IOException
+    {
+        try {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            try {
+                tf.setAttribute("indent-number", new Integer(2));
+            } catch (IllegalArgumentException iae) {
+                //Ignore the IAE. Should not fail the writeout even the
+                //transformer provider does not support "indent-number".
+            }
+            Transformer t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            //Transformer resets the "indent" info if the "result" is a StreamResult with
+            //an OutputStream object embedded, creating a Writer object on top of that
+            //OutputStream object however works.
+            t.transform(new DOMSource(doc),
+                        new StreamResult(new BufferedWriter(new OutputStreamWriter(out, "UTF-8"))));
+        } catch(TransformerException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    // BEGIN Android-added: Filter out non-Element nodes.
+    static class NodeListAdapter implements NodeList {
+        private final List<? extends Node> delegate;
+
+        public NodeListAdapter(List<? extends Node> delegate) {
+            this.delegate = Objects.requireNonNull(delegate);
+        }
+
+        @Override public Node item(int index) {
+            if (index < 0 || index >= delegate.size()) {
+                return null;
+            }
+            return delegate.get(index);
+        }
+        @Override public int getLength() { return delegate.size(); }
+    }
+
+    private static NodeList elementNodesOf(NodeList xmlKids) {
+        List<Element> elements = new ArrayList<>(xmlKids.getLength());
+        for (int i = 0; i < xmlKids.getLength(); ++i) {
+            Node node = xmlKids.item(i);
+            if (node instanceof Element) {
+                elements.add((Element) node);
+            }
+        }
+        return new NodeListAdapter(elements);
+    }
+    // END Android-added: Filter out non-Element nodes.
+
+    /**
+     * Recursively traverse the specified preferences node and store
+     * the described preferences into the system or current user
+     * preferences tree, as appropriate.
+     */
+    private static void ImportSubtree(Preferences prefsNode, Element xmlNode) {
+        NodeList xmlKids = xmlNode.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        xmlKids = elementNodesOf(xmlKids);
+        int numXmlKids = xmlKids.getLength();
+        /*
+         * We first lock the node, import its contents and get
+         * child nodes. Then we unlock the node and go to children
+         * Since some of the children might have been concurrently
+         * deleted we check for this.
+         */
+        Preferences[] prefsKids;
+        /* Lock the node */
+        synchronized (((AbstractPreferences)prefsNode).lock) {
+            //If removed, return silently
+            if (((AbstractPreferences)prefsNode).isRemoved())
+                return;
+
+            // Import any preferences at this node
+            Element firstXmlKid = (Element) xmlKids.item(0);
+            ImportPrefs(prefsNode, firstXmlKid);
+            prefsKids = new Preferences[numXmlKids - 1];
+
+            // Get involved children
+            for (int i=1; i < numXmlKids; i++) {
+                Element xmlKid = (Element) xmlKids.item(i);
+                prefsKids[i-1] = prefsNode.node(xmlKid.getAttribute("name"));
+            }
+        } // unlocked the node
+        // import children
+        for (int i=1; i < numXmlKids; i++)
+            ImportSubtree(prefsKids[i-1], (Element)xmlKids.item(i));
+    }
+
+    /**
+     * Import the preferences described by the specified XML element
+     * (a map from a preferences document) into the specified
+     * preferences node.
+     */
+    private static void ImportPrefs(Preferences prefsNode, Element map) {
+        NodeList entries = map.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        entries = elementNodesOf(entries);
+        for (int i=0, numEntries = entries.getLength(); i < numEntries; i++) {
+            Element entry = (Element) entries.item(i);
+            prefsNode.put(entry.getAttribute("key"),
+                          entry.getAttribute("value"));
+        }
+    }
+
+    /**
+     * Export the specified Map<String,String> to a map document on
+     * the specified OutputStream as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     */
+    static void exportMap(OutputStream os, Map<String, String> map) throws IOException {
+        Document doc = createPrefsDoc("map");
+        Element xmlMap = doc.getDocumentElement( ) ;
+        xmlMap.setAttribute("MAP_XML_VERSION", MAP_XML_VERSION);
+
+        for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<String, String> e = i.next();
+            Element xe = (Element)
+                xmlMap.appendChild(doc.createElement("entry"));
+            xe.setAttribute("key",   e.getKey());
+            xe.setAttribute("value", e.getValue());
+        }
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Import Map from the specified input stream, which is assumed
+     * to contain a map document as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.  The
+     * key-value pairs specified in the XML document will be put into
+     * the specified Map.  (If this Map is empty, it will contain exactly
+     * the key-value pairs int the XML-document when this method returns.)
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importMap(InputStream is, Map<String, String> m)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            Element xmlMap = doc.getDocumentElement();
+            // check version
+            String mapVersion = xmlMap.getAttribute("MAP_XML_VERSION");
+            if (mapVersion.compareTo(MAP_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Preferences map file format version " + mapVersion +
+                " is not supported. This java installation can read" +
+                " versions " + MAP_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            NodeList entries = xmlMap.getChildNodes();
+            for (int i=0, numEntries=entries.getLength(); i<numEntries; i++) {
+                // BEGIN Android-added: Filter out non-Element nodes.
+                // Android xml serializer generates one-char Text nodes with a single
+                // new-line character between expected Element nodes. OpenJDK code wasn't
+                // expecting anything else than Element nodes.
+                if (!(entries.item(i) instanceof Element)) {
+                    continue;
+                }
+                // END Android-added: Filter out non-Element nodes.
+                Element entry = (Element) entries.item(i);
+                m.put(entry.getAttribute("key"), entry.getAttribute("value"));
+            }
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PREFS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PREFS_DTD));
+                is.setSystemId(PREFS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+}
diff --git a/android-35/java/util/prefs/package-info.java b/android-35/java/util/prefs/package-info.java
new file mode 100644
index 0000000..e125ed4
--- /dev/null
+++ b/android-35/java/util/prefs/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This package allows applications to store and retrieve user and system
+ * preference and configuration data. This data is stored persistently in an
+ * implementation-dependent backing store. There are two separate trees of
+ * preference nodes, one for user preferences and one for system preferences.
+ *
+ * @since 1.4
+ */
+package java.util.prefs;
diff --git a/android-35/java/util/random/RandomGenerator.java b/android-35/java/util/random/RandomGenerator.java
new file mode 100644
index 0000000..72c8ac2
--- /dev/null
+++ b/android-35/java/util/random/RandomGenerator.java
@@ -0,0 +1,1565 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.random;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Objects;
+import java.util.concurrent.ThreadLocalRandom;
+import jdk.internal.util.random.RandomSupport;
+import jdk.internal.util.random.RandomSupport.*;
+
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/**
+ * The {@link RandomGenerator} interface is designed to provide a common
+ * protocol for objects that generate random or (more typically) pseudorandom
+ * sequences of numbers (or Boolean values). Such a sequence may be obtained by
+ * either repeatedly invoking a method that returns a single pseudorandomly
+ * chosen value, or by invoking a method that returns a stream of
+ * pseudorandomly chosen values.
+ *
+ * <p> Ideally, given an implicitly or explicitly specified range of values,
+ * each value would be chosen independently and uniformly from that range. In
+ * practice, one may have to settle for some approximation to independence and
+ * uniformity.
+ *
+ * <p> In the case of {@code int}, {@code long}, and {@code boolean} values, if
+ * there is no explicit specification of range, then the range includes all
+ * possible values of the type. In the case of {@code float} and {@code double}
+ * values, first a value is always chosen uniformly from the set of
+ * 2<sup><i>w</i></sup> values between 0.0 (inclusive) and 1.0 (exclusive),
+ * where <i>w</i> is 23 for {@code float} values and 52 for {@code double}
+ * values, such that adjacent values differ by 2<sup>&minus;<i>w</i></sup>
+ * (notice that this set is a <i>subset</i> of the set of
+ * <i>all representable floating-point values</i> between 0.0 (inclusive) and 1.0 (exclusive));
+ * then if an explicit range was specified, then the chosen number is
+ * computationally scaled and translated so as to appear to have been chosen
+ * approximately uniformly from that explicit range.
+ *
+ * <p> Each method that returns a stream produces a stream of values each of
+ * which is chosen in the same manner as for a method that returns a single
+ * pseudorandomly chosen value. For example, if {@code r} implements
+ * {@link RandomGenerator}, then the method call {@code r.ints(100)} returns a
+ * stream of 100 {@code int} values. These are not necessarily the exact same
+ * values that would have been returned if instead {@code r.nextInt()} had been
+ * called 100 times; all that is guaranteed is that each value in the stream is
+ * chosen in a similar pseudorandom manner from the same range.
+ *
+ * <p> Every object that implements the {@link RandomGenerator} interface by
+ * using a pseudorandom algorithm is assumed to contain a finite amount of
+ * state. Using such an object to generate a pseudorandomly chosen value alters
+ * its state by computing a new state as a function of the current state,
+ * without reference to any information other than the current state. The number
+ * of distinct possible states of such an object is called its <i>period</i>.
+ * (Some implementations of the {@link RandomGenerator} interface may be truly
+ * random rather than pseudorandom, for example relying on the statistical
+ * behavior of a physical object to derive chosen values. Such implementations
+ * do not have a fixed period.)
+ *
+ * <p> As a rule, objects that implement the {@link RandomGenerator} interface
+ * need not be thread-safe. It is recommended that multithreaded applications
+ * use either {@link ThreadLocalRandom} or (preferably) pseudorandom number
+ * generators that implement the {@link SplittableGenerator} or
+ * {@link JumpableGenerator} interface.
+ *
+ * <p> Objects that implement {@link RandomGenerator} are typically not
+ * cryptographically secure. Consider instead using {@link SecureRandom} to get
+ * a cryptographically secure pseudorandom number generator for use by
+ * security-sensitive applications. Note, however, that {@link SecureRandom}
+ * does implement the {@link RandomGenerator} interface, so that instances of
+ * {@link SecureRandom} may be used interchangeably with other types of
+ * pseudorandom generators in applications that do not require a secure
+ * generator.
+ *
+ * <p>Unless explicit stated otherwise, the use of null for any method argument
+ * will cause a NullPointerException.
+ *
+ * @since 17
+ *
+ */
+public interface RandomGenerator {
+     /**
+     * Returns an instance of {@link RandomGenerator} that utilizes the
+     * {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+     *
+     * @param name  Name of random number generator
+     *              <a href="package-summary.html#algorithms">algorithm</a>
+     *
+     * @return An instance of {@link RandomGenerator}
+     *
+     * @throws NullPointerException if name is null
+     * @throws IllegalArgumentException if the named algorithm is not found
+     */
+    static RandomGenerator of(String name) {
+        Objects.requireNonNull(name);
+
+        return RandomGeneratorFactory.of(name, RandomGenerator.class);
+    }
+
+    /**
+     * Returns a {@link RandomGenerator} meeting the minimal requirement
+     * of having an <a href="package-summary.html#algorithms">algorithm</a>
+     * whose state bits are greater than or equal 64.
+     *
+     * @implSpec  Since algorithms will improve over time, there is no
+     * guarantee that this method will return the same algorithm over time.
+     * <p> The default implementation selects L32X64MixRandom.
+     *
+     * @return a {@link RandomGenerator}
+     */
+    static RandomGenerator getDefault() {
+        return of("L32X64MixRandom");
+    }
+
+    /**
+     * Return true if the implementation of RandomGenerator (algorithm) has been
+     * marked for deprecation.
+     *
+     * @implNote Random number generator algorithms evolve over time; new
+     * algorithms will be introduced and old algorithms will
+     * lose standing. If an older algorithm is deemed unsuitable
+     * for continued use, it will be marked as deprecated to indicate
+     * that it may be removed at some point in the future.
+     *
+     * @return true if the implementation of RandomGenerator (algorithm) has been
+     *         marked for deprecation
+     *
+     * @implSpec The default implementation checks for the @Deprecated annotation.
+     */
+     default boolean isDeprecated() {
+        return this.getClass().isAnnotationPresent(Deprecated.class);
+     }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code double} values.
+     *
+     * @return a stream of pseudorandomly chosen {@code double} values
+     *
+     * @implNote It is permitted to implement this method in a manner equivalent to
+     * {@link RandomGenerator#doubles(long) doubles}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextDouble nextDouble}().
+     */
+    default DoubleStream doubles() {
+        return DoubleStream.generate(this::nextDouble).sequential();
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code double} values, where each value is between the specified origin
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code double} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code randomNumberOrigin} is not finite,
+     *         or {@code randomNumberBound} is not finite, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implNote It is permitted to implement this method in a manner equivalent to
+     * {@link RandomGenerator#doubles(long, double, double) doubles}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}, randomNumberOrigin, randomNumberBound).
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextDouble(double, double) nextDouble}(randomNumberOrigin, randomNumberBound).
+     */
+    default DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return DoubleStream.generate(() -> nextDouble(randomNumberOrigin, randomNumberBound)).sequential();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code double} values.
+     *
+     * @param streamSize the number of values to generate
+     *
+     * @return a stream of pseudorandomly chosen {@code double} values
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextDouble nextDouble()}.
+     */
+    default DoubleStream doubles(long streamSize) {
+        RandomSupport.checkStreamSize(streamSize);
+
+        return doubles().limit(streamSize);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code double} values, where each value is
+     * between the specified origin (inclusive) and the specified bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code double} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is less than zero,
+     *         or {@code randomNumberOrigin} is not finite,
+     *         or {@code randomNumberBound} is not finite, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextDouble(double, double)  nextDouble}(randomNumberOrigin, randomNumberBound).
+     */
+    default DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                double randomNumberBound) {
+        RandomSupport.checkStreamSize(streamSize);
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return doubles(randomNumberOrigin, randomNumberBound).limit(streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code int} values.
+     *
+     * @return a stream of pseudorandomly chosen {@code int} values
+     *
+     * @implNote It is permitted to implement this method in a manner
+     * equivalent to {@link RandomGenerator#ints(long) ints}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextInt() nextInt}().
+     */
+    default IntStream ints() {
+        return IntStream.generate(this::nextInt).sequential();
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code int} values, where each value is between the specified origin
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code int} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implNote It is permitted to implement this method in a manner equivalent to
+     * {@link RandomGenerator#ints(long, int, int) ints}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}, randomNumberOrigin, randomNumberBound).
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextInt(int, int) nextInt}(randomNumberOrigin, randomNumberBound).
+     */
+    default IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return IntStream.generate(() -> nextInt(randomNumberOrigin, randomNumberBound)).sequential();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code int} values.
+     *
+     * @param streamSize the number of values to generate
+     *
+     * @return a stream of pseudorandomly chosen {@code int} values
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextInt() nextInt}().
+     */
+    default IntStream ints(long streamSize) {
+        RandomSupport.checkStreamSize(streamSize);
+
+        return ints().limit(streamSize);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code int} values, where each value is between
+     * the specified origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code int} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextInt(int, int) nextInt}(randomNumberOrigin, randomNumberBound).
+     */
+    default IntStream ints(long streamSize, int randomNumberOrigin,
+              int randomNumberBound) {
+        RandomSupport.checkStreamSize(streamSize);
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return ints(randomNumberOrigin, randomNumberBound).limit(streamSize);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code long} values.
+     *
+     * @return a stream of pseudorandomly chosen {@code long} values
+     *
+     * @implNote It is permitted to implement this method in a manner
+     * equivalent to {@link RandomGenerator#longs(long) longs}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextLong() nextLong}().
+     */
+    default LongStream longs() {
+        return LongStream.generate(this::nextLong).sequential();
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandomly chosen
+     * {@code long} values, where each value is between the specified origin
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code long} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implNote It is permitted to implement this method in a manner equivalent to
+     * {@link RandomGenerator#longs(long, long, long) longs}
+     * ({@link Long#MAX_VALUE Long.MAX_VALUE}, randomNumberOrigin, randomNumberBound).
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextLong(long, long) nextLong}(randomNumberOrigin, randomNumberBound).
+     */
+    default LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return LongStream.generate(() -> nextLong(randomNumberOrigin, randomNumberBound)).sequential();
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code long} values.
+     *
+     * @param streamSize the number of values to generate
+     *
+     * @return a stream of pseudorandomly chosen {@code long} values
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     *
+     * @implSpec The default implementation produces a sequential stream
+     * that repeatedly calls {@link RandomGenerator#nextLong() nextLong}().
+     */
+    default LongStream longs(long streamSize) {
+        RandomSupport.checkStreamSize(streamSize);
+
+        return longs().limit(streamSize);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandomly chosen {@code long} values, where each value is between
+     * the specified origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the least value that can be produced
+     * @param randomNumberBound the upper bound (exclusive) for each value produced
+     *
+     * @return a stream of pseudorandomly chosen {@code long} values, each between
+     *         the specified origin (inclusive) and the specified bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     *
+     * @implSpec The default implementation produces a sequential stream that repeatedly
+     * calls {@link RandomGenerator#nextLong(long, long) nextLong}(randomNumberOrigin, randomNumberBound).
+     */
+    default LongStream longs(long streamSize, long randomNumberOrigin,
+                long randomNumberBound) {
+        RandomSupport.checkStreamSize(streamSize);
+        RandomSupport.checkRange(randomNumberOrigin, randomNumberBound);
+
+        return longs(randomNumberOrigin, randomNumberBound).limit(streamSize);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code boolean} value.
+     *
+     * <p> The default implementation tests the high-order bit (sign bit) of a
+     * value produced by {@link RandomGenerator#nextInt() nextInt}(), on the
+     * grounds that some algorithms for pseudorandom number generation produce
+     * values whose high-order bits have better statistical quality than the
+     * low-order bits.
+     *
+     * @return a pseudorandomly chosen {@code boolean} value
+     *
+     * @implSpec The default implementation produces a result based on the
+     * sign bit of a number generated by {@link #nextInt()}.
+     */
+    default boolean nextBoolean() {
+        return nextInt() < 0;
+    }
+
+    /**
+     * Fills a user-supplied byte array with generated byte values
+     * pseudorandomly chosen uniformly from the range of values between -128
+     * (inclusive) and 127 (inclusive).
+     *
+     * @implNote Algorithm used to fill the byte array;
+     *           <pre>{@code
+     *           void nextBytes(byte[] bytes) {
+     *               int i = 0;
+     *               int len = bytes.length;
+     *               for (int words = len >> 3; words--> 0; ) {
+     *                   long rnd = nextLong();
+     *                   for (int n = 8; n--> 0; rnd >>>= Byte.SIZE)
+     *                       bytes[i++] = (byte)rnd;
+     *               }
+     *               if (i < len)
+     *                   for (long rnd = nextLong(); i < len; rnd >>>= Byte.SIZE)
+     *                       bytes[i++] = (byte)rnd;
+     *           }}</pre>
+     *
+     * @param  bytes the byte array to fill with pseudorandom bytes
+     * @throws NullPointerException if bytes is null
+     *
+     * @implSpec The default implementation produces results from repeated calls
+     * to {@link #nextLong()}.
+     */
+    default void nextBytes(byte[] bytes) {
+        int i = 0;
+        int len = bytes.length;
+        for (int words = len >> 3; words--> 0; ) {
+            long rnd = nextLong();
+            for (int n = 8; n--> 0; rnd >>>= Byte.SIZE)
+                bytes[i++] = (byte)rnd;
+        }
+        if (i < len)
+            for (long rnd = nextLong(); i < len; rnd >>>= Byte.SIZE)
+                bytes[i++] = (byte)rnd;
+    }
+
+    /**
+     * Returns a pseudorandom {@code float} value between zero (inclusive) and
+     * one (exclusive).
+     *
+     * @return a pseudorandom {@code float} value between zero (inclusive) and one (exclusive)
+     *
+     * @implSpec The default implementation uses the 24 high-order bits from a call to
+     * {@link RandomGenerator#nextInt() nextInt}().
+     */
+    default float nextFloat() {
+        return (nextInt() >>> 8) * 0x1.0p-24f;
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code float} value between zero
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive) for the returned value.
+     *        Must be positive and finite
+     *
+     * @return a pseudorandomly chosen {@code float} value between
+     *         zero (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code bound} is not
+     *         both positive and finite
+     *
+     * @implSpec The default implementation checks that {@code bound} is a
+     * positive finite float. Then invokes {@code nextFloat()}, scaling
+     * the result so that the final result lies between {@code 0.0f} (inclusive)
+     * and {@code bound} (exclusive).
+     */
+    default float nextFloat(float bound) {
+        RandomSupport.checkBound(bound);
+
+        return RandomSupport.boundedNextFloat(this, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code float} value between the
+     * specified origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value that can be returned
+     * @param bound the upper bound (exclusive)
+     *
+     * @return a pseudorandomly chosen {@code float} value between the
+     *         origin (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code origin} is not finite,
+     *         or {@code bound} is not finite, or {@code origin}
+     *         is greater than or equal to {@code bound}
+     *
+     * @implSpec The default implementation checks that {@code origin} and
+     * {@code bound} are positive finite floats. Then invokes
+     * {@code nextFloat()}, scaling and translating the result so that the final
+     * result lies between {@code origin} (inclusive) and {@code bound}
+     * (exclusive).
+     */
+    default float nextFloat(float origin, float bound) {
+        RandomSupport.checkRange(origin, bound);
+
+        return RandomSupport.boundedNextFloat(this, origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero (inclusive) and
+     * one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero (inclusive)
+     *         and one (exclusive)
+     *
+     * @implSpec The default implementation uses the 53 high-order bits from a call to
+     * {@link RandomGenerator#nextLong nextLong}().
+     */
+    default double nextDouble() {
+        return (nextLong() >>> 11) * 0x1.0p-53;
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code double} value between zero
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive) for the returned value.
+     *        Must be positive and finite
+     *
+     * @return a pseudorandomly chosen {@code double} value between
+     *         zero (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code bound} is not
+     *         both positive and finite
+     *
+     * @implSpec The default implementation checks that {@code bound} is a
+     * positive finite double. Then invokes {@code nextDouble()}, scaling
+     * the result so that the final result lies between {@code 0.0} (inclusive)
+     * and {@code bound} (exclusive).
+     */
+    default double nextDouble(double bound) {
+        RandomSupport.checkBound(bound);
+
+        return RandomSupport.boundedNextDouble(this, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code double} value between the
+     * specified origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value that can be returned
+     * @param bound the upper bound (exclusive) for the returned value
+     *
+     * @return a pseudorandomly chosen {@code double} value between the
+     *         origin (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code origin} is not finite,
+     *         or {@code bound} is not finite, or {@code origin}
+     *         is greater than or equal to {@code bound}
+     *
+     * @implSpec The default implementation checks that {@code origin} and
+     * {@code bound} are positive finite doubles. Then calls
+     * {@code nextDouble()}, scaling and translating the result so that the final
+     * result lies between {@code origin} (inclusive) and {@code bound}
+     * (exclusive).
+     */
+    default double nextDouble(double origin, double bound) {
+        RandomSupport.checkRange(origin, bound);
+
+        return RandomSupport.boundedNextDouble(this, origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code int} value.
+     *
+     * @return a pseudorandomly chosen {@code int} value
+     *
+     * @implSpec The default implementation uses the 32 high-order bits from a call to
+     * {@link RandomGenerator#nextLong nextLong}().
+     */
+    default int nextInt() {
+        return (int)(nextLong() >>> 32);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code int} value between zero
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive) for the returned value.
+     * Must be positive.
+     *
+     * @return a pseudorandomly chosen {@code int} value between
+     *         zero (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     *
+     * @implSpec The default implementation checks that {@code bound} is a
+     * positive {@code int}. Then invokes {@code nextInt()}, limiting the result
+     * to be greater than or equal zero and less than {@code bound}. If {@code bound}
+     * is a power of two then limiting is a simple masking operation. Otherwise,
+     * the result is re-calculated by invoking {@code nextInt()} until the
+     * result is greater than or equal zero and less than {@code bound}.
+     */
+    default int nextInt(int bound) {
+        RandomSupport.checkBound(bound);
+
+        return RandomSupport.boundedNextInt(this, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value that can be returned
+     * @param bound the upper bound (exclusive) for the returned value
+     *
+     * @return a pseudorandomly chosen {@code int} value between the
+     *         origin (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     *
+     * @implSpec The default implementation checks that {@code origin} and
+     * {@code bound} are positive {@code ints}. Then invokes {@code nextInt()},
+     * limiting the result to be greater that or equal {@code origin} and less
+     * than {@code bound}. If {@code bound} is a power of two then limiting is a
+     * simple masking operation. Otherwise, the result is re-calculated  by
+     * invoking {@code nextInt()} until the result is greater than or equal
+     * {@code origin} and less than {@code bound}.
+     */
+    default int nextInt(int origin, int bound) {
+        RandomSupport.checkRange(origin, bound);
+
+        return RandomSupport.boundedNextInt(this, origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code long} value.
+     *
+     * @return a pseudorandomly chosen {@code long} value
+     */
+    long nextLong();
+
+    /**
+     * Returns a pseudorandomly chosen {@code long} value between zero
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive) for the returned value.
+     * Must be positive.
+     *
+     * @return a pseudorandomly chosen {@code long} value between
+     *         zero (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     *
+     * @implSpec The default implementation checks that {@code bound} is a
+     * positive  {@code long}. Then invokes {@code nextLong()}, limiting the
+     * result to be greater than or equal zero and less than {@code bound}. If
+     * {@code bound} is a power of two then limiting is a simple masking
+     * operation. Otherwise, the result is re-calculated by invoking
+     * {@code nextLong()} until the result is greater than or equal zero and
+     * less than {@code bound}.
+     */
+    default long nextLong(long bound) {
+        RandomSupport.checkBound(bound);
+
+        return RandomSupport.boundedNextLong(this, bound);
+    }
+
+    /**
+     * Returns a pseudorandomly chosen {@code long} value between the
+     * specified origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value that can be returned
+     * @param bound the upper bound (exclusive) for the returned value
+     *
+     * @return a pseudorandomly chosen {@code long} value between the
+     *         origin (inclusive) and the bound (exclusive)
+     *
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     *
+     * @implSpec The default implementation checks that {@code origin} and
+     * {@code bound} are positive {@code longs}. Then invokes {@code nextLong()},
+     * limiting the result to be greater than or equal {@code origin} and less
+     * than {@code bound}. If {@code bound} is a power of two then limiting is a
+     * simple masking operation. Otherwise, the result is re-calculated by
+     * invoking {@code nextLong()} until the result is greater than or equal
+     * {@code origin} and less than {@code bound}.
+     */
+    default long nextLong(long origin, long bound) {
+        RandomSupport.checkRange(origin, bound);
+
+        return RandomSupport.boundedNextLong(this, origin, bound);
+    }
+
+    /**
+     * Returns a {@code double} value pseudorandomly chosen from a Gaussian
+     * (normal) distribution whose mean is 0 and whose standard deviation is 1.
+     *
+     * @return a {@code double} value pseudorandomly chosen from a
+     *         Gaussian distribution
+     *
+     * @implSpec The default implementation uses McFarland's fast modified
+     * ziggurat algorithm (largely table-driven, with rare cases handled by
+     * computation and rejection sampling). Walker's alias method for sampling
+     * a discrete distribution also plays a role.
+     */
+    default double nextGaussian() {
+        // See Knuth, TAOCP, Vol. 2, 3rd edition, Section 3.4.1 Algorithm C.
+        return RandomSupport.computeNextGaussian(this);
+    }
+
+    /**
+     * Returns a {@code double} value pseudorandomly chosen from a Gaussian
+     * (normal) distribution with a mean and standard deviation specified by the
+     * arguments.
+     *
+     * @param mean the mean of the Gaussian distribution to be drawn from
+     * @param stddev the standard deviation (square root of the variance)
+     *        of the Gaussian distribution to be drawn from
+     *
+     * @return a {@code double} value pseudorandomly chosen from the
+     *         specified Gaussian distribution
+     *
+     * @throws IllegalArgumentException if {@code stddev} is negative
+     *
+     * @implSpec The default implementation uses McFarland's fast modified
+     * ziggurat algorithm (largely table-driven, with rare cases handled by
+     * computation and rejection sampling). Walker's alias method for sampling
+     * a discrete distribution also plays a role.
+     */
+    default double nextGaussian(double mean, double stddev) {
+        if (stddev < 0.0) throw new IllegalArgumentException("standard deviation must be non-negative");
+
+        return mean + stddev * RandomSupport.computeNextGaussian(this);
+    }
+
+    /**
+     * Returns a nonnegative {@code double} value pseudorandomly chosen from
+     * an exponential distribution whose mean is 1.
+     *
+     * @return a nonnegative {@code double} value pseudorandomly chosen from an
+     *         exponential distribution
+     *
+     * @implSpec The default implementation uses McFarland's fast modified
+     * ziggurat algorithm (largely table-driven, with rare cases handled by
+     * computation and rejection sampling). Walker's alias method for sampling
+     * a discrete distribution also plays a role.
+     */
+    default double nextExponential() {
+        return RandomSupport.computeNextExponential(this);
+    }
+
+    /**
+     * The {@link StreamableGenerator} interface augments the
+     * {@link RandomGenerator} interface to provide methods that return streams
+     * of {@link RandomGenerator} objects. Ideally, such a stream of objects
+     * would have the property that the behavior of each object is statistically
+     * independent of all the others. In practice, one may have to settle for
+     * some approximation to this property.
+     *
+     * <p> A generator that implements interface {@link SplittableGenerator} may
+     * choose to use its {@link SplittableGenerator#splits splits}() method to
+     * implement the {@link StreamableGenerator#rngs rngs}() method required by this
+     * interface.
+     *
+     * <p> A generator that implements interface {@link JumpableGenerator} may
+     * choose to use its {@link JumpableGenerator#jumps() jumps}() method to implement the
+     * {@link StreamableGenerator#rngs() rngs}() method required by this interface.
+     *
+     * <p> A generator that implements interface {@link LeapableGenerator} may
+     * choose to use its {@link LeapableGenerator#leaps() leaps}() method to
+     * implement the {@link StreamableGenerator#rngs() rngs}() method required by this
+     * interface.
+     *
+     * <p> Objects that implement {@link StreamableGenerator} are typically not
+     * cryptographically secure. Consider instead using {@link SecureRandom} to
+     * get a cryptographically secure pseudo-random number generator for use by
+     * security-sensitive applications.
+     */
+    interface StreamableGenerator extends RandomGenerator {
+
+        /**
+         * Returns an instance of {@link StreamableGenerator} that utilizes the
+         * {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+         *
+         * @param name  Name of random number generator
+         *              <a href="package-summary.html#algorithms">algorithm</a>
+         *
+         * @return An instance of {@link StreamableGenerator}
+         *
+         * @throws NullPointerException if name is null
+         * @throws IllegalArgumentException if the named algorithm is not found
+         */
+        static StreamableGenerator of(String name) {
+            Objects.requireNonNull(name);
+
+            return RandomGeneratorFactory.of(name, StreamableGenerator.class);
+        }
+
+        /**
+         * Returns an effectively unlimited stream of objects, each of which
+         * implements the {@link RandomGenerator} interface. Ideally the
+         * generators in the stream will appear to be statistically independent.
+         * The new generators are of the same
+         * <a href="package-summary.html#algorithms">algorithm</a> as this generator.
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @implNote It is permitted to implement this method in a manner
+         *           equivalent to {@link StreamableGenerator#rngs(long) rngs}
+         *           ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+         */
+        Stream<RandomGenerator> rngs();
+
+        /**
+         * Returns an effectively unlimited stream of objects, each of which
+         * implements the {@link RandomGenerator} interface. Ideally the
+         * generators in the stream will appear to be statistically independent.
+         * The new generators are of the same
+         * <a href="package-summary.html#algorithms">algorithm</a> as this generator.
+         *
+         * @param streamSize the number of generators to generate
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is
+         *         less than zero
+         *
+         * @implSpec The default implementation calls {@link StreamableGenerator#rngs() rngs}() and
+         * then limits its length to {@code streamSize}.
+         */
+        default Stream<RandomGenerator> rngs(long streamSize) {
+            RandomSupport.checkStreamSize(streamSize);
+
+            return rngs().limit(streamSize);
+        }
+    }
+
+    /**
+     * This interface is designed to provide a common protocol for objects that
+     * generate sequences of pseudorandom values and can be <i>split</i> into
+     * two objects (the original one and a new one) each of which obey that same
+     * protocol (and therefore can be recursively split indefinitely).
+     *
+     * <p> Ideally, all {@link SplittableGenerator} objects produced by
+     * recursive splitting from a single original {@link SplittableGenerator}
+     * object are statistically independent of one another and individually
+     * uniform. Therefore we would expect the set of values collectively
+     * generated by a set of such objects to have the same statistical
+     * properties as if the same quantity of values were generated by a single
+     * thread using a single {@link SplittableGenerator} object. In practice,
+     * one must settle for some approximation to independence and uniformity.
+     *
+     * <p> Methods are provided to perform a single splitting operation and also
+     * to produce a stream of generators split off from the original (by either
+     * iterative or recursive splitting, or a combination).
+     *
+     * <p> Objects that implement {@link SplittableGenerator} are typically not
+     * cryptographically secure. Consider instead using {@link SecureRandom} to
+     * get a cryptographically secure pseudo-random number generator for use by
+     * security-sensitive applications.
+     */
+    interface SplittableGenerator extends StreamableGenerator {
+
+        /**
+         * Returns an instance of {@link SplittableGenerator} that utilizes the
+         * {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+         *
+         * @param name  Name of random number generator
+         *              <a href="package-summary.html#algorithms">algorithm</a>
+         *
+         * @return An instance of {@link SplittableGenerator}
+         *
+         * @throws NullPointerException if name is null
+         * @throws IllegalArgumentException if the named algorithm is not found
+         */
+        static SplittableGenerator of(String name) {
+            Objects.requireNonNull(name);
+
+            return RandomGeneratorFactory.of(name, SplittableGenerator.class);
+        }
+
+        /**
+         * Returns a new pseudorandom number generator, split off from this one,
+         * that implements the {@link RandomGenerator} and
+         * {@link SplittableGenerator} interfaces.
+         *
+         * <p> This pseudorandom number generator may be used as a source of
+         * pseudorandom bits used to initialize the state of the new one.
+         *
+         * @return a new object that implements the {@link RandomGenerator} and
+         *         {@link SplittableGenerator} interfaces
+         */
+        SplittableGenerator split();
+
+        /**
+         * Returns a new pseudorandom number generator, split off from this one,
+         * that implements the {@link RandomGenerator} and
+         * {@link SplittableGenerator} interfaces.
+         *
+         * @param source a {@link SplittableGenerator} instance to be used instead
+         *               of this one as a source of pseudorandom bits used to
+         *               initialize the state of the new ones.
+         *
+         * @return an object that implements the {@link RandomGenerator} and
+         *         {@link SplittableGenerator} interfaces
+         *
+         * @throws NullPointerException if source is null
+         */
+        SplittableGenerator split(SplittableGenerator source);
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link SplittableGenerator}
+         * interface.
+         *
+         * <p> This pseudorandom number generator may be used as a source of
+         * pseudorandom bits used to initialize the state the new ones.
+         *
+         * @implNote It is permitted to implement this method in a manner
+         * equivalent to {@link SplittableGenerator#splits(long) splits}
+         * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+         *
+         * @return a stream of {@link SplittableGenerator} objects
+         *
+         * @implSpec The default implementation invokes
+         * {@link SplittableGenerator#splits(SplittableGenerator) splits(this)}.
+         */
+        default Stream<SplittableGenerator> splits() {
+            return this.splits(this);
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link SplittableGenerator} interface.
+         *
+         * <p> This pseudorandom number generator may be used as a source of
+         * pseudorandom bits used to initialize the state the new ones.
+         *
+         * @param streamSize the number of values to generate
+         *
+         * @return a stream of {@link SplittableGenerator} objects
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is
+         *         less than zero
+         */
+        Stream<SplittableGenerator> splits(long streamSize);
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link SplittableGenerator}
+         * interface.
+         *
+         * @param source a {@link SplittableGenerator} instance to be used instead
+         *               of this one as a source of pseudorandom bits used to
+         *               initialize the state of the new ones.
+         *
+         * @return a stream of {@link SplittableGenerator} objects
+         *
+         * @implNote It is permitted to implement this method in a manner
+         *           equivalent to {@link SplittableGenerator#splits(long, SplittableGenerator) splits}
+         *           ({@link Long#MAX_VALUE Long.MAX_VALUE}, source).
+         *
+         * @throws NullPointerException if source is null
+         */
+        Stream<SplittableGenerator> splits(SplittableGenerator source);
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link SplittableGenerator} interface.
+         *
+         * @param streamSize the number of values to generate
+         * @param source a {@link SplittableGenerator} instance to be used instead
+         *               of this one as a source of pseudorandom bits used to
+         *               initialize the state of the new ones.
+         *
+         * @return a stream of {@link SplittableGenerator} objects
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is
+         *         less than zero
+         * @throws NullPointerException if source is null
+         */
+        Stream<SplittableGenerator> splits(long streamSize, SplittableGenerator source);
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link RandomGenerator}
+         * interface. Ideally the generators in the stream will appear to be
+         * statistically independent.
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @implSpec The default implementation calls {@link SplittableGenerator#splits() splits}().
+         */
+        default Stream<RandomGenerator> rngs() {
+            return this.splits().map(x -> x);
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link RandomGenerator} interface. Ideally the generators in the
+         * stream will appear to be statistically independent.
+         *
+         * @param streamSize the number of generators to generate
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is
+         *         less than zero
+         *
+         * @implSpec The default implementation calls {@link SplittableGenerator#splits(long) splits}(streamSize).
+         */
+        default Stream<RandomGenerator> rngs(long streamSize) {
+            return this.splits(streamSize).map(x -> x);
+        }
+    }
+
+    /**
+     * This interface is designed to provide a common protocol for objects that
+     * generate pseudorandom values and can easily <i>jump</i> forward, by a
+     * moderate amount (ex. 2<sup>64</sup>) to a distant point in the state cycle.
+     *
+     * <p> Ideally, all {@link JumpableGenerator} objects produced by iterative
+     * jumping from a single original {@link JumpableGenerator} object are
+     * statistically independent of one another and individually uniform. In
+     * practice, one must settle for some approximation to independence and
+     * uniformity. In particular, a specific implementation may assume that each
+     * generator in a stream produced by the
+     * {@link JumpableGenerator#jump jump()} method is used to produce a number
+     * of values no larger than either 2<sup>64</sup> or the square root of its
+     * period. Implementors are advised to use algorithms whose period is at
+     * least 2<sup>127</sup>.
+     *
+     * <p> Methods are provided to perform a single jump operation and also to
+     * produce a stream of generators produced from the original by iterative
+     * copying and jumping of internal state. A typical strategy for a
+     * multithreaded application is to create a single {@link JumpableGenerator}
+     * object, calls its {@link JumpableGenerator#jump jump}() method exactly
+     * once, and then parcel out generators from the resulting stream, one to
+     * each thread. It is generally not a good idea to call
+     * {@link JumpableGenerator#jump jump}() on a generator that was itself
+     * produced by the {@link JumpableGenerator#jump jump}() method, because the
+     * result may be a generator identical to another generator already produce
+     * by that call to the {@link JumpableGenerator#jump jump}() method. For
+     * this reason, the return type of the {@link JumpableGenerator#jumps jumps}()
+     * method is {@code Stream<RandomGenerator>} rather than
+     * {@code Stream<JumpableGenerator>}, even though the actual generator
+     * objects in that stream likely do also implement the
+     * {@link JumpableGenerator} interface.
+     *
+     * <p> Objects that implement {@link JumpableGenerator} are typically not
+     * cryptographically secure. Consider instead using {@link SecureRandom} to
+     * get a cryptographically secure pseudo-random number generator for use by
+     * security-sensitive applications.
+     */
+    interface JumpableGenerator extends StreamableGenerator {
+
+        /**
+         * Returns an instance of {@link JumpableGenerator} that utilizes the
+         * {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+         *
+         * @param name  Name of random number generator
+         *              <a href="package-summary.html#algorithms">algorithm</a>
+         *
+         * @return An instance of {@link JumpableGenerator}
+         *
+         * @throws NullPointerException if name is null
+         * @throws IllegalArgumentException if the named algorithm is not found
+         */
+        static JumpableGenerator of(String name) {
+            Objects.requireNonNull(name);
+
+            return RandomGeneratorFactory.of(name, JumpableGenerator.class);
+        }
+
+        /**
+         * Returns a new generator whose internal state is an exact copy of this
+         * generator (therefore their future behavior should be identical if
+         * subjected to the same series of operations).
+         *
+         * @return a new object that is a copy of this generator
+         */
+        JumpableGenerator copy();
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to jump
+         * forward a large, fixed distance (typically 2<sup>64</sup> or more)
+         * within its state cycle.
+         */
+        void jump();
+
+        /**
+         * Returns the distance by which the
+         * {@link JumpableGenerator#jump jump}() method will jump forward within
+         * the state cycle of this generator object.
+         *
+         * @return the default jump distance (as a {@code double} value)
+         */
+        double jumpDistance();
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link RandomGenerator}
+         * interface.
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @implNote It is permitted to implement this method in a manner equivalent to
+         * {@link JumpableGenerator#jumps(long) jumps}
+         * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+         *
+         * @implSpec The default implementation produces a sequential stream that  repeatedly
+         * calls {@link JumpableGenerator#copy copy}() and {@link JumpableGenerator#jump jump}()
+         * on this generator, and the copies become the generators produced by the stream.
+         */
+        default Stream<RandomGenerator> jumps() {
+            return Stream.generate(this::copyAndJump).sequential();
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link RandomGenerator} interface.
+         *
+         * @param streamSize the number of generators to generate
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is less than zero
+         *
+         * @implSpec The default implementation produces a sequential stream that  repeatedly
+         * calls {@link JumpableGenerator#copy copy}() and {@link JumpableGenerator#jump jump}()
+         * on this generator, and the copies become the generators produced by the stream.
+         */
+        default Stream<RandomGenerator> jumps(long streamSize) {
+            return jumps().limit(streamSize);
+        }
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link RandomGenerator}
+         * interface. Ideally the generators in the stream will appear to be
+         * statistically independent.
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @implSpec The default implementation calls {@link JumpableGenerator#jump jump}().
+         */
+        default Stream<RandomGenerator> rngs() {
+            return this.jumps();
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link RandomGenerator} interface. Ideally the generators in the
+         * stream will appear to be statistically independent.
+         *
+         * @param streamSize the number of generators to generate
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is less than zero
+         *
+         * @implSpec The default implementation calls {@link JumpableGenerator#jumps(long) jumps}(streamSize).
+         */
+        default Stream<RandomGenerator> rngs(long streamSize) {
+            return this.jumps(streamSize);
+        }
+
+        /**
+         * Copy this generator, jump this generator forward, then return the
+         * copy.
+         *
+         * @return a copy of this generator object before the jump occurred
+         *
+         * @implSpec The default implementation copies this, jumps and then
+         * returns the copy.
+         */
+        default RandomGenerator copyAndJump() {
+            RandomGenerator result = copy();
+            jump();
+
+            return result;
+        }
+
+    }
+
+    /**
+     * This interface is designed to provide a common protocol for objects that
+     * generate sequences of pseudorandom values and can easily not only jump
+     * but also <i>leap</i> forward, by a large amount (ex. 2<sup>128</sup>), to
+     * a very distant point in the state cycle.
+     *
+     * Typically one will construct a series of {@link LeapableGenerator}
+     * objects by iterative leaping from a single original
+     * {@link LeapableGenerator} object, and then for each such object produce a
+     * subseries of objects by iterative jumping. There is little conceptual
+     * difference between leaping and jumping, but typically a leap will be a
+     * very long jump in the state cycle (perhaps distance 2<sup>128</sup> or
+     * so).
+     *
+     * <p> Ideally, all {@link LeapableGenerator} objects produced by iterative
+     * leaping and jumping from a single original {@link LeapableGenerator}
+     * object are statistically independent of one another and individually
+     * uniform. In practice, one must settle for some approximation to
+     * independence and uniformity. In particular, a specific implementation may
+     * assume that each generator in a stream produced by the {@code leaps}
+     * method is used to produce (by jumping) a number of objects no larger than
+     * 2<sup>64</sup>. Implementors are advised to use algorithms whose period
+     * is at least 2<sup>191</sup>.
+     *
+     * <p> Methods are provided to perform a single leap operation and also to
+     * produce a stream of generators produced from the original by iterative
+     * copying and leaping of internal state. The generators produced must
+     * implement the {@link JumpableGenerator} interface but need not also
+     * implement the {@link LeapableGenerator} interface. A typical strategy for
+     * a multithreaded application is to create a single
+     * {@link LeapableGenerator} object, calls its {@code leaps} method exactly
+     * once, and then parcel out generators from the resulting stream, one to
+     * each thread. Then the {@link JumpableGenerator#jump() jump}() method of
+     * each such generator be called to produce a substream of generator
+     * objects.
+     *
+     * <p> Objects that implement {@link LeapableGenerator} are typically not
+     * cryptographically secure. Consider instead using {@link SecureRandom} to
+     * get a cryptographically secure pseudo-random number generator for use by
+     * security-sensitive applications.
+     */
+    interface LeapableGenerator extends JumpableGenerator {
+
+        /**
+         * Returns an instance of {@link LeapableGenerator} that utilizes the
+         * {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+         *
+         * @param name  Name of random number generator
+         *              <a href="package-summary.html#algorithms">algorithm</a>
+         *
+         * @return An instance of {@link LeapableGenerator}
+         *
+         * @throws NullPointerException if name is null
+         * @throws IllegalArgumentException if the named algorithm is not found
+         */
+        static LeapableGenerator of(String name) {
+            Objects.requireNonNull(name);
+
+            return RandomGeneratorFactory.of(name, LeapableGenerator.class);
+        }
+
+        /**
+         * Returns a new generator whose internal state is an exact copy of this
+         * generator (therefore their future behavior should be identical if
+         * subjected to the same series of operations).
+         *
+         * @return a new object that is a copy of this generator
+         */
+        LeapableGenerator copy();
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to leap
+         * forward a large, fixed distance (typically 2<sup>96</sup> or more)
+         * within its state cycle.
+         */
+        void leap();
+
+        /**
+         * Returns the distance by which the
+         * {@link LeapableGenerator#leap() leap}() method will leap forward within
+         * the state cycle of this generator object.
+         *
+         * @return the default leap distance (as a {@code double} value)
+         */
+        double leapDistance();
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the {@link JumpableGenerator}
+         * interface.
+         *
+         * @return a stream of objects that implement the {@link JumpableGenerator} interface
+         *
+         * @implNote It is permitted to implement this method in a manner equivalent to
+         * {@link LeapableGenerator#leaps(long) leaps}
+         * ({@link  Long#MAX_VALUE Long.MAX_VALUE}).
+         *
+         * @implSpec The default implementation produces a sequential stream that  repeatedly
+         * calls {@link LeapableGenerator#copy() copy}() and {@link LeapableGenerator#leap() leap}()
+         * on this generator, and the copies become the generators produced by the stream.
+         */
+        default Stream<JumpableGenerator> leaps() {
+            return Stream.generate(this::copyAndLeap).sequential();
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link JumpableGenerator} interface.
+         *
+         * @param streamSize the number of generators to generate
+         *
+         * @return a stream of objects that implement the {@link JumpableGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is less than zero
+         *
+         * @implSpec The default implementation produces a sequential stream that  repeatedly
+         *           calls {@link LeapableGenerator#copy() copy}() and {@link LeapableGenerator#leap() leap}()
+         *           on this generator, and the copies become the generators produced by the stream.
+         */
+        default Stream<JumpableGenerator> leaps(long streamSize) {
+            return leaps().limit(streamSize);
+        }
+
+        /**
+         * Copy this generator, leap this generator forward, then return the
+         * copy.
+         *
+         * @return a copy of this generator object before the leap occurred
+         *
+         * @implSpec The default implementation copies this, leaps and then
+         * returns the copy.
+         */
+        default JumpableGenerator copyAndLeap() {
+            JumpableGenerator result = copy();
+            leap();
+            return result;
+        }
+
+    }
+
+    /**
+     * This interface is designed to provide a common protocol for objects that
+     * generate sequences of pseudorandom values and can easily <i>jump</i>
+     * forward, by an arbitrary amount, to a distant point in the state cycle.
+     *
+     * <p> Ideally, all {@link ArbitrarilyJumpableGenerator} objects produced by
+     * iterative jumping from a single original
+     * {@link ArbitrarilyJumpableGenerator} object are statistically independent
+     * of one another and individually uniform, provided that they do not
+     * traverse overlapping portions of the state cycle. In practice, one must
+     * settle for some approximation to independence and uniformity. In
+     * particular, a specific implementation may assume that each generator in a
+     * stream produced by the {@link JumpableGenerator#jump() jump}() method is
+     * used to produce a number of values no larger than the jump distance
+     * specified. Implementors are advised to use algorithms whose period is at
+     * least 2<sup>127</sup>.
+     *
+     * <p> For many applications, it suffices to jump forward by a power of two
+     * or some small multiple of a power of two, but this power of two may not
+     * be representable as a {@code long} value. To avoid the use of
+     * {@link BigInteger} values as jump distances, {@code double} values are
+     * used instead.
+     *
+     * <p> Methods are provided to perform a single jump operation and also to
+     * produce a stream of generators produced from the original by iterative
+     * copying and jumping of internal state. A typical strategy for a
+     * multithreaded application is to create a single
+     * {@link ArbitrarilyJumpableGenerator} object, call its
+     * {@link JumpableGenerator#jump() jump}() method exactly once, and then
+     * parcel out generators from the resulting stream, one to each thread.
+     * However, each generator produced also has type
+     * {@link ArbitrarilyJumpableGenerator}; with care, different jump distances
+     * can be used to traverse the entire state cycle in various ways.
+     *
+     * <p> Objects that implement {@link ArbitrarilyJumpableGenerator} are
+     * typically not cryptographically secure. Consider instead using
+     * {@link SecureRandom} to get a cryptographically secure pseudo-random
+     * number generator for use by security-sensitive applications.
+     */
+    interface ArbitrarilyJumpableGenerator extends LeapableGenerator {
+
+        /**
+         * Returns an instance of {@link ArbitrarilyJumpableGenerator} that
+         * utilizes the {@code name} <a href="package-summary.html#algorithms">algorithm</a>.
+         *
+         * @param name  Name of random number generator
+         *              <a href="package-summary.html#algorithms">algorithm</a>
+         *
+         * @return An instance of {@link ArbitrarilyJumpableGenerator}
+         *
+         * @throws NullPointerException if name is null
+         * @throws IllegalArgumentException if the named algorithm is not found
+         */
+        static ArbitrarilyJumpableGenerator of(String name) {
+            Objects.requireNonNull(name);
+
+            return RandomGeneratorFactory.of(name, ArbitrarilyJumpableGenerator.class);
+        }
+
+        /**
+         * Returns a new generator whose internal state is an exact copy of this
+         * generator (therefore their future behavior should be identical if
+         * subjected to the same series of operations).
+         *
+         * @return a new object that is a copy of this generator
+         */
+        ArbitrarilyJumpableGenerator copy();
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to jump
+         * forward a distance equal to 2<sup>{@code logDistance}</sup> within
+         * its state cycle.
+         *
+         * @param logDistance the base-2 logarithm of the distance to jump forward within the state
+         *                    cycle
+         *
+         * @throws IllegalArgumentException if {@code logDistance} is
+         *                                  2<sup>{@code logDistance}</sup> is
+         *                                  greater than the period of this generator
+         */
+        void jumpPowerOfTwo(int logDistance);
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to jump
+         * forward a specified distance within its state cycle.
+         *
+         * @param distance the distance to jump forward within the state cycle
+         *
+         * @throws IllegalArgumentException if {@code distance} is not greater than
+         *                                  or equal to 0.0, or is greater than the
+         *                                  period of this generator
+         */
+        void jump(double distance);
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to jump
+         * forward a large, fixed distance (typically 2<sup>64</sup> or more)
+         * within its state cycle. The distance used is that returned by method
+         * {@link ArbitrarilyJumpableGenerator#jumpDistance() jumpDistance}().
+         *
+         * @implSpec The default implementation invokes jump(jumpDistance()).
+         */
+        default void jump() { jump(jumpDistance()); }
+
+        /**
+         * Returns an effectively unlimited stream of new pseudorandom number
+         * generators, each of which implements the
+         * {@link ArbitrarilyJumpableGenerator} interface, produced by jumping
+         * copies of this generator by different integer multiples of the
+         * specified jump distance.
+         *
+         * @param distance a distance to jump forward within the state cycle
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code distance} is not greater than
+         *                                  or equal to 0.0, or is greater than the
+         *                                  period of this generator
+         *
+         * @implSpec The default implementation is equivalent to
+         * {@link ArbitrarilyJumpableGenerator#jumps(long) jumps}
+         * ({@link Long#MAX_VALUE Long.MAX_VALUE}).
+         */
+        default Stream<ArbitrarilyJumpableGenerator> jumps(double distance) {
+            return Stream.generate(() -> copyAndJump(distance)).sequential();
+        }
+
+        /**
+         * Returns a stream producing the given {@code streamSize} number of new
+         * pseudorandom number generators, each of which implements the
+         * {@link ArbitrarilyJumpableGenerator} interface, produced by jumping
+         * copies of this generator by different integer multiples of the
+         * specified jump distance.
+         *
+         * @param streamSize the number of generators to generate
+         * @param distance   a distance to jump forward within the state cycle
+         *
+         * @return a stream of objects that implement the {@link RandomGenerator} interface
+         *
+         * @throws IllegalArgumentException if {@code streamSize} is less than zero or if
+         *                                  {@code distance} is not greater than
+         *                                  or equal to 0.0, or is greater than the
+         *                                  period of this generator
+         *
+         * @implSpec The default implementation is equivalent to
+         * jumps(distance).limit(streamSize).
+         */
+        default Stream<ArbitrarilyJumpableGenerator> jumps(long streamSize, double distance) {
+            return jumps(distance).limit(streamSize);
+        }
+
+        /**
+         * Alter the state of this pseudorandom number generator so as to jump
+         * forward a very large, fixed distance (typically 2<sup>128</sup> or
+         * more) within its state cycle. The distance used is that returned by
+         * method
+         * {@link ArbitrarilyJumpableGenerator#leapDistance() leapDistance}().
+         */
+        default void leap() { jump(leapDistance()); }
+
+        /**
+         * Copy this generator, jump this generator forward, then return the
+         * copy.
+         *
+         * @param distance a distance to jump forward within the state cycle
+         *
+         * @return a copy of this generator object before the jump occurred
+         *
+         * @throws IllegalArgumentException if {@code distance} is not greater than
+         *                                  or equal to 0.0, or is greater than the
+         *                                  period of this generator
+         *
+         * @implSpec The default implementation copies this, jumps(distance) and then
+         * returns the copy.
+         */
+        default ArbitrarilyJumpableGenerator copyAndJump(double distance) {
+            ArbitrarilyJumpableGenerator result = copy();
+            jump(distance);
+
+            return result;
+        }
+
+    }
+}
diff --git a/android-35/java/util/random/RandomGeneratorFactory.java b/android-35/java/util/random/RandomGeneratorFactory.java
new file mode 100644
index 0000000..aab9591
--- /dev/null
+++ b/android-35/java/util/random/RandomGeneratorFactory.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.random;
+
+import java.lang.reflect.Constructor;
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator;
+import java.util.random.RandomGenerator.JumpableGenerator;
+import java.util.random.RandomGenerator.LeapableGenerator;
+import java.util.random.RandomGenerator.SplittableGenerator;
+import java.util.random.RandomGenerator.StreamableGenerator;
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
+import jdk.random.L128X1024MixRandom;
+import jdk.random.L128X128MixRandom;
+import jdk.random.L128X256MixRandom;
+import jdk.random.L32X64MixRandom;
+import jdk.random.L64X1024MixRandom;
+import jdk.random.L64X128MixRandom;
+import jdk.random.L64X128StarStarRandom;
+import jdk.random.L64X256MixRandom;
+import jdk.random.Xoroshiro128PlusPlus;
+import jdk.random.Xoshiro256PlusPlus;
+
+/**
+ * This is a factory class for generating multiple random number generators
+ * of a specific <a href="package-summary.html#algorithms">algorithm</a>.
+ * {@link RandomGeneratorFactory} also provides
+ * methods for selecting random number generator algorithms.
+ *
+ * A specific {@link RandomGeneratorFactory} can be located by using the
+ * {@link RandomGeneratorFactory#of(String)} method, where the argument string
+ * is the name of the <a href="package-summary.html#algorithms">algorithm</a>
+ * required. The method
+ * {@link RandomGeneratorFactory#all()} produces a non-empty {@link Stream} of all available
+ * {@link RandomGeneratorFactory RandomGeneratorFactorys} that can be searched
+ * to locate a {@link RandomGeneratorFactory} suitable to the task.
+ *
+ * There are three methods for constructing a RandomGenerator instance,
+ * depending on the type of initial seed required.
+ * {@link RandomGeneratorFactory#create(long)} is used for long
+ * seed construction,
+ * {@link RandomGeneratorFactory#create(byte[])} is used for byte[]
+ * seed construction, and
+ * {@link RandomGeneratorFactory#create()} is used for random seed
+ * construction. Example;
+ *
+ * <pre>{@code
+ *    RandomGeneratorFactory<RandomGenerator> factory = RandomGeneratorFactory.of("Random");
+ *
+ *     for (int i = 0; i < 10; i++) {
+ *         new Thread(() -> {
+ *             RandomGenerator random = factory.create(100L);
+ *             System.out.println(random.nextDouble());
+ *         }).start();
+ *     }
+ * }</pre>
+ *
+ * RandomGeneratorFactory also provides methods describing the attributes (or properties)
+ * of a generator and can be used to select random number generator
+ * <a href="package-summary.html#algorithms">algorithms</a>.
+ * These methods are typically used in
+ * conjunction with {@link RandomGeneratorFactory#all()}. In this example, the code
+ * locates the {@link RandomGeneratorFactory} that produces
+ * {@link RandomGenerator RandomGenerators}
+ * with the highest number of state bits.
+ *
+ * <pre>{@code
+ *     RandomGeneratorFactory<RandomGenerator> best = RandomGeneratorFactory.all()
+ *         .sorted(Comparator.comparingInt(RandomGenerator::stateBits).reversed())
+ *         .findFirst()
+ *         .orElse(RandomGeneratorFactory.of("Random"));
+ *     System.out.println(best.name() + " in " + best.group() + " was selected");
+ *
+ *     RandomGenerator rng = best.create();
+ *     System.out.println(rng.nextLong());
+ * }</pre>
+ *
+ * @since 17
+ *
+ * @see java.util.random
+ *
+ */
+public final class RandomGeneratorFactory<T extends RandomGenerator> {
+    /**
+     * Instance provider class of random number algorithm.
+     */
+    private final Provider<? extends RandomGenerator> provider;
+
+    /**
+     * Provider RandomGeneratorProperties annotation.
+     */
+    private volatile RandomGeneratorProperties properties;
+
+    /**
+     * Default provider constructor.
+     */
+    private volatile Constructor<T> ctor;
+
+    /**
+     * Provider constructor with long seed.
+     */
+    private Constructor<T> ctorLong;
+
+    /**
+     * Provider constructor with byte[] seed.
+     */
+    private Constructor<T> ctorBytes;
+
+
+    private static class FactoryMapHolder {
+        static final Map<String, Provider<? extends RandomGenerator>> FACTORY_MAP = createFactoryMap();
+
+        /**
+         * Returns the factory map, lazily constructing map on first use.
+         *
+         * @return Map of RandomGeneratorFactory classes.
+         */
+        private static Map<String, Provider<? extends RandomGenerator>> createFactoryMap() {
+            // Android-changed: don't use SPI, list all available algorithms.
+            /*
+            return ServiceLoader
+                .load(RandomGenerator.class)
+                .stream()
+                .filter(p -> !p.type().isInterface())
+                .collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity()));
+            */
+            return Map.ofEntries(
+                    entryFor(L32X64MixRandom.class, L32X64MixRandom::new),
+                    entryFor(L64X128MixRandom.class, L64X128MixRandom::new),
+                    entryFor(L64X128StarStarRandom.class, L64X128StarStarRandom::new),
+                    entryFor(L64X256MixRandom.class, L64X256MixRandom::new),
+                    entryFor(L64X1024MixRandom.class, L64X1024MixRandom::new),
+                    entryFor(L128X128MixRandom.class, L128X128MixRandom::new),
+                    entryFor(L128X256MixRandom.class, L128X256MixRandom::new),
+                    entryFor(L128X1024MixRandom.class, L128X1024MixRandom::new),
+                    entryFor(Xoroshiro128PlusPlus.class, Xoroshiro128PlusPlus::new),
+                    entryFor(Xoshiro256PlusPlus.class, Xoshiro256PlusPlus::new));
+        }
+
+        // BEGIN Android-added: method to create Map.Entry<String, Provider> for a RandomGenerator.
+        private static <T extends RandomGenerator> Map.Entry<String, Provider<T>> entryFor(
+                Class<T> clazz, Supplier<T> supplier) {
+            return Map.entry(clazz.getSimpleName(), new Provider<>() {
+                @Override
+                public Class<? extends T> type() {
+                    return clazz;
+                }
+
+                @Override
+                public T get() {
+                    return supplier.get();
+                }
+            });
+        }
+        // END Android-added: method to create Map.Entry<String, Provider> for a RandomGenerator.
+    }
+
+    /**
+     * Private constructor.
+     *
+     * @param provider  Provider class to wrap.
+     */
+    private RandomGeneratorFactory(Provider<? extends RandomGenerator> provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the factory map, lazily constructing map on first call.
+     *
+     * @return Map of RandomGeneratorFactory classes.
+     */
+    private static Map<String, Provider<? extends RandomGenerator>> getFactoryMap() {
+        return FactoryMapHolder.FACTORY_MAP;
+    }
+
+    /**
+     * Return the annotation for the specified provider.
+     *
+     * @return RandomGeneratorProperties annotation for the specified provider.
+     */
+     private RandomGeneratorProperties getProperties() {
+        if (properties == null) {
+            synchronized (provider) {
+                if (properties == null) {
+                    properties = provider.type().getDeclaredAnnotation(RandomGeneratorProperties.class);
+                    Objects.requireNonNull(properties, provider.type() + " missing annotation");
+                }
+            }
+        }
+
+        return properties;
+    }
+
+    /**
+     * Return true if the provider is a subclass of the category.
+     *
+     * @param category Interface category, sub-interface of {@link RandomGenerator}.
+     *
+     * @return true if the provider is a subclass of the category.
+     */
+    private boolean isSubclass(Class<? extends RandomGenerator> category) {
+        return isSubclass(category, provider);
+    }
+
+    /**
+     * Return true if the provider is a subclass of the category.
+     *
+     * @param category Interface category, sub-interface of {@link RandomGenerator}.
+     * @param provider Provider that is being filtered.
+     *
+     * @return true if the provider is a subclass of the category.
+     */
+    private static boolean isSubclass(Class<? extends RandomGenerator> category,
+                                      Provider<? extends RandomGenerator> provider) {
+        return provider != null && category.isAssignableFrom(provider.type());
+    }
+
+    /**
+     * Returns the provider matching name and category.
+     *
+     * @param name      Name of RandomGenerator
+     * @param category  Interface category, sub-interface of {@link RandomGenerator}.
+     *
+     * @return A provider matching name and category.
+     *
+     * @throws IllegalArgumentException if provider is not a subclass of category.
+     */
+    private static Provider<? extends RandomGenerator> findProvider(String name,
+                                                                    Class<? extends RandomGenerator> category)
+            throws IllegalArgumentException {
+        Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
+        Provider<? extends RandomGenerator> provider = fm.get(name);
+        if (provider == null) {
+            throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" +
+                                                name +
+                                                "\" is available");
+        } else if (!isSubclass(category, provider)) {
+            throw new IllegalArgumentException("The random number generator algorithm \"" +
+                                                name +
+                                                "\" is not implemented with the interface \"" +
+                                                category.getSimpleName() +
+                                                "\"");
+        }
+        return provider;
+    }
+
+    /**
+     * Returns a {@link RandomGenerator} that utilizes the {@code name}
+     * <a href="package-summary.html#algorithms">algorithm</a>.
+     *
+     * @param name      Name of random number algorithm to use
+     * @param category  Sub-interface of {@link RandomGenerator} to type check
+     * @param <T>       Sub-interface of {@link RandomGenerator} to produce
+     *
+     * @return An instance of {@link RandomGenerator}
+     *
+     * @throws IllegalArgumentException when either the name or category is null
+     */
+    static <T extends RandomGenerator> T of(String name, Class<T> category)
+            throws IllegalArgumentException {
+        @SuppressWarnings("unchecked")
+        T uncheckedRandomGenerator = (T)findProvider(name, category).get();
+        return uncheckedRandomGenerator;
+    }
+
+    /**
+     * Returns a {@link RandomGeneratorFactory} that will produce instances
+     * of {@link RandomGenerator} that utilizes the named algorithm.
+     *
+     * @param name  Name of random number algorithm to use
+     * @param category Sub-interface of {@link RandomGenerator} to type check
+     * @param <T> Sub-interface of {@link RandomGenerator} to produce
+     *
+     * @return Factory of {@link RandomGenerator}
+     *
+     * @throws IllegalArgumentException when either the name or category is null
+     */
+    static <T extends RandomGenerator> RandomGeneratorFactory<T> factoryOf(String name, Class<T> category)
+            throws IllegalArgumentException {
+        Provider<? extends RandomGenerator> uncheckedProvider = findProvider(name, category);
+        return new RandomGeneratorFactory<>(uncheckedProvider);
+    }
+
+    /**
+     * Fetch the required constructors for class of random number algorithm.
+     *
+     * @param randomGeneratorClass class of random number algorithm (provider)
+     */
+    private void getConstructors(Class<? extends RandomGenerator> randomGeneratorClass) {
+        if (ctor == null) {
+            synchronized (provider) {
+                if (ctor == null) {
+                    PrivilegedExceptionAction<Constructor<?>[]> ctorAction = randomGeneratorClass::getConstructors;
+                    try {
+                        @SuppressWarnings("removal")
+                        Constructor<?>[] ctors = AccessController.doPrivileged(ctorAction);
+
+                        Constructor<T> tmpCtor = null;
+                        Constructor<T> tmpCtorLong = null;
+                        Constructor<T> tmpCtorBytes = null;
+
+
+                        for (Constructor<?> ctorGeneric : ctors) {
+                            @SuppressWarnings("unchecked")
+                            Constructor<T> ctorSpecific = (Constructor<T>) ctorGeneric;
+                            final Class<?>[] parameterTypes = ctorSpecific.getParameterTypes();
+
+                            if (parameterTypes.length == 0) {
+                                tmpCtor = ctorSpecific;
+                            } else if (parameterTypes.length == 1) {
+                                Class<?> argType = parameterTypes[0];
+
+                                if (argType == long.class) {
+                                    tmpCtorLong = ctorSpecific;
+                                } else if (argType == byte[].class) {
+                                    tmpCtorBytes = ctorSpecific;
+                                }
+                            }
+                        }
+
+                        if (tmpCtor == null) {
+                            throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor");
+                        }
+
+                        // Store specialized constructors first, guarded by ctor
+                        ctorBytes = tmpCtorBytes;
+                        ctorLong = tmpCtorLong;
+                        ctor = tmpCtor;
+                    } catch (PrivilegedActionException ex) {
+                        // Do nothing
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Ensure all the required constructors are fetched.
+     */
+    private void ensureConstructors() {
+        getConstructors(provider.type());
+    }
+
+    /**
+     * Returns a {@link RandomGeneratorFactory} that can produce instances of
+     * {@link RandomGenerator} that utilize the {@code name}
+     * <a href="package-summary.html#algorithms">algorithm</a>.
+     *
+     * @implSpec Availability is determined by RandomGeneratorFactory using the
+     * service provider API to locate implementations of the RandomGenerator interface.
+     *
+     * @param name  Name of random number generator
+     * <a href="package-summary.html#algorithms">algorithm</a>
+     * @param <T> Sub-interface of {@link RandomGenerator} to produce
+     *
+     * @return {@link RandomGeneratorFactory} of {@link RandomGenerator}
+     *
+     * @throws NullPointerException if name is null
+     * @throws IllegalArgumentException if the named algorithm is not found
+     */
+    public static <T extends RandomGenerator> RandomGeneratorFactory<T> of(String name) {
+        Objects.requireNonNull(name);
+        @SuppressWarnings("unchecked")
+        RandomGeneratorFactory<T> factory =
+                (RandomGeneratorFactory<T>)factoryOf(name, RandomGenerator.class);
+        return factory;
+    }
+
+    /**
+     * Returns a {@link RandomGeneratorFactory} meeting the minimal requirement
+     * of having an algorithm whose state bits are greater than or equal 64.
+     *
+     * @implSpec  Since algorithms will improve over time, there is no
+     * guarantee that this method will return the same algorithm over time.
+     *
+     * @return a {@link RandomGeneratorFactory}
+     */
+    public static RandomGeneratorFactory<RandomGenerator> getDefault() {
+        return factoryOf("L32X64MixRandom", RandomGenerator.class);
+    }
+
+    /**
+     * Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
+     *
+     * RandomGenerators that are marked as deprecated are not included in the result.
+     *
+     * @implSpec Availability is determined by RandomGeneratorFactory using the service provider API
+     * to locate implementations of the RandomGenerator interface.
+     *
+     * @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
+     */
+    public static Stream<RandomGeneratorFactory<RandomGenerator>> all() {
+        Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
+        return fm.values()
+                 .stream()
+                 .filter(p -> !p.type().isAnnotationPresent(Deprecated.class) &&
+                              p.type().isAnnotationPresent(RandomGeneratorProperties.class))
+                 .map(RandomGeneratorFactory::new);
+    }
+
+    /**
+     * Return the name of the <a href="package-summary.html#algorithms">algorithm</a>
+     * used by the random number generator.
+     *
+     * @return Name of the <a href="package-summary.html#algorithms">algorithm</a>.
+     */
+    public String name() {
+        return provider.type().getSimpleName();
+    }
+
+    /**
+     * Return the group name of the <a href="package-summary.html#algorithms">algorithm</a>
+     * used by the random number generator.
+     *
+     * @return Group name of the <a href="package-summary.html#algorithms">algorithm</a>.
+     */
+    public String group() {
+        return getProperties().group();
+    }
+
+    /**
+     * Returns number of bits used by the <a href="package-summary.html#algorithms">algorithm</a>
+     * to maintain state of seed.
+     *
+     * @return number of bits used by the <a href="package-summary.html#algorithms">algorithm</a>
+     *         to maintain state of seed.
+     */
+    public int stateBits() {
+        RandomGeneratorProperties properties = getProperties();
+        int i = properties.i();
+        int k = properties.k();
+
+        return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
+    }
+
+    /**
+     * Returns the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
+     *
+     * @return the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
+     */
+    public int equidistribution() {
+        return getProperties().equidistribution();
+    }
+
+    /**
+     * Return the period of the <a href="package-summary.html#algorithms">algorithm</a>
+     * used by the random number generator.
+     * Returns BigInteger.ZERO if period is not determinable.
+     *
+     * @return BigInteger period.
+     */
+    public BigInteger period() {
+        RandomGeneratorProperties properties = getProperties();
+        int i = properties.i();
+        int j = properties.j();
+        int k = properties.k();
+
+        if (i == 0 && j == 0 && k == 0) {
+            return BigInteger.ZERO;
+        } else {
+            return BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
+        }
+    }
+
+    /**
+     * Return true if random generator is computed using an arithmetic
+     * <a href="package-summary.html#algorithms">algorithm</a>
+     * and is statistically deterministic.
+     *
+     * @return true if random generator is statistical.
+     */
+    public boolean isStatistical() {
+        return !getProperties().isStochastic();
+    }
+
+    /**
+     * Return true if random generator is computed using external or entropic
+     * sources as inputs.
+     *
+     * @return true if random generator is stochastic.
+     */
+    public boolean isStochastic() {
+        return getProperties().isStochastic();
+    }
+
+    /**
+     * Return true if random generator uses a hardware device (HRNG) to produce
+     * entropic input.
+     *
+     * @return true if random generator is generated by hardware.
+     */
+    public boolean isHardware() {
+        return getProperties().isHardware();
+    }
+
+    /**
+     * Return true if random generator can jump an arbitrarily specified distant
+     * point in the state cycle.
+     *
+     * @return true if random generator is arbitrarily jumpable.
+     */
+    public boolean isArbitrarilyJumpable() {
+        return isSubclass(ArbitrarilyJumpableGenerator.class);
+    }
+
+    /**
+     * Return true if random generator can jump a specified distant point in
+     * the state cycle.
+     *
+     * @return true if random generator is jumpable.
+     */
+    public boolean isJumpable() {
+        return isSubclass(JumpableGenerator.class);
+    }
+
+    /**
+     * Return true if random generator is jumpable and can leap to a very distant
+     * point in the state cycle.
+     *
+     * @return true if random generator is leapable.
+     */
+    public boolean isLeapable() {
+        return isSubclass(LeapableGenerator.class);
+    }
+
+    /**
+     * Return true if random generator can be cloned into a separate object with
+     * the same properties but positioned further in the state cycle.
+     *
+     * @return true if random generator is splittable.
+     */
+    public boolean isSplittable() {
+        return isSubclass(SplittableGenerator.class);
+    }
+
+    /**
+     * Return true if random generator can be used to create
+     * {@link java.util.stream.Stream Streams} of random numbers.
+     *
+     * @return true if random generator is streamable.
+     */
+    public boolean isStreamable() {
+        return isSubclass(StreamableGenerator.class);
+    }
+
+    /**
+     * Return true if the implementation of RandomGenerator (algorithm) has been
+     * marked for deprecation.
+     *
+     * @implNote Random number generator algorithms evolve over time; new
+     *           algorithms will be introduced and old algorithms will
+     *           lose standing. If an older algorithm is deemed unsuitable
+     *           for continued use, it will be marked as deprecated to indicate
+     *           that it may be removed at some point in the future.
+     *
+     * @return true if the implementation of RandomGenerator (algorithm) has been
+     *         marked for deprecation
+     */
+     public boolean isDeprecated() {
+        return provider.type().isAnnotationPresent(Deprecated.class);
+     }
+
+    /**
+     * Create an instance of {@link RandomGenerator} based on
+     * <a href="package-summary.html#algorithms">algorithm</a> chosen.
+     *
+     * @return new in instance of {@link RandomGenerator}.
+     *
+     */
+    public T create() {
+        try {
+            ensureConstructors();
+            return ctor.newInstance();
+        } catch (Exception ex) {
+            // Should never happen.
+            throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor", ex);
+        }
+    }
+
+    /**
+     * Create an instance of {@link RandomGenerator} based on
+     * <a href="package-summary.html#algorithms">algorithm</a> chosen
+     * providing a starting long seed. If long seed is not supported by an
+     * algorithm then the no argument form of create is used.
+     *
+     * @param seed long random seed value.
+     *
+     * @return new in instance of {@link RandomGenerator}.
+     */
+    public T create(long seed) {
+        try {
+            ensureConstructors();
+            return ctorLong.newInstance(seed);
+        } catch (Exception ex) {
+            return create();
+        }
+    }
+
+    /**
+     * Create an instance of {@link RandomGenerator} based on
+     * <a href="package-summary.html#algorithms">algorithm</a> chosen
+     * providing a starting byte[] seed. If byte[] seed is not supported by an
+     * <a href="package-summary.html#algorithms">algorithm</a> then the no
+     * argument form of create is used.
+     *
+     * @param seed byte array random seed value.
+     *
+     * @return new in instance of {@link RandomGenerator}.
+     *
+     * @throws NullPointerException if seed is null.
+     */
+    public T create(byte[] seed) {
+        Objects.requireNonNull(seed, "seed must not be null");
+        try {
+            ensureConstructors();
+            return ctorBytes.newInstance(seed);
+        } catch (Exception ex) {
+            return create();
+        }
+    }
+
+}
+
+
diff --git a/android-35/java/util/random/package-info.java b/android-35/java/util/random/package-info.java
new file mode 100644
index 0000000..bfc6186
--- /dev/null
+++ b/android-35/java/util/random/package-info.java
@@ -0,0 +1,634 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Android-changed: removed service loader API sentence.
+
+/**
+ * This package contains classes and interfaces that support a generic API
+ * for random number generation.
+ *
+ * <p>These classes and interfaces support the definition and use of "random
+ * generators", a term covering what have traditionally been called "random
+ * number generators" as well as generators of other sorts of randomly chosen
+ * values (eg. booleans). These classes and interfaces cover not only
+ * deterministic (pseudorandom) algorithms but also generators of values that
+ * use some "truly random" physical source (stochastic algorithms perhaps making
+ * use of thermal noise, for example, or quantum-mechanical effects).
+ *
+ * <p> The principal interface is {@link RandomGenerator}, which provides
+ * methods for requesting individual values of type {@code int}, {@code long},
+ * {@code float}, {@code double}, or {@code boolean} chosen pseudorandomly
+ * from a uniform distribution; methods for requesting values of type
+ * {@code double} chosen pseudorandomly from a normal distribution or from an
+ * exponential distribution; and methods for creating streams of values of type
+ * {@code int}, {@code long}, or {@code double} chosen pseudorandomly from a
+ * uniform distribution (such streams are spliterator-based, allowing for
+ * parallel processing of their elements). There are also static factory methods
+ * for creating an instance of a specific random number generator algorithm
+ * given its name.
+ *
+ * <p> The principal supporting class is {@link RandomGeneratorFactory}. This
+ * can be used to generate multiple random number generators for a specific
+ * algorithm. {@link RandomGeneratorFactory} also provides methods for
+ * selecting random number generator algorithms.
+ *
+ * <p> An important subsidiary interface is
+ * {@link RandomGenerator.StreamableGenerator}, which provides methods for
+ * creating spliterator-based streams of {@link RandomGenerator} objects,
+ * allowing for parallel processing of these objects using multiple threads.
+ * Unlike {@link java.util.Random}, most implementations of
+ * {@link RandomGenerator} are <i>not</i> thread-safe. The intent is that
+ * instances should not be shared among threads; rather, each thread should have
+ * its own random generator(s) to use. The various pseudorandom algorithms
+ * provided by this package are designed so that multiple instances will (with
+ * very high probability) behave as if statistically independent.
+ *
+ * <p> For many purposes, these are the only two interfaces that a consumer of
+ * pseudorandom values will need. There are also some more specialized
+ * interfaces that describe more specialized categories of random number
+ * generators {@link RandomGenerator.SplittableGenerator SplittableGenerator},
+ * {@link RandomGenerator.JumpableGenerator JumpableGenerator},
+ * {@link RandomGenerator.LeapableGenerator LeapableGenerator}, and
+ * {@link RandomGenerator.ArbitrarilyJumpableGenerator ArbitrarilyJumpableGenerator}
+ * that have specific strategies for creating statistically independent instances.
+ *
+ * <h2>Using the Random Number Generator Interfaces</h2>
+ *
+ * To get started, an application should first create one instance of a
+ * generator class. Assume that the contents of the package
+ * {@link java.util.random} has been imported:
+ *
+ * <blockquote>{@code import java.util.random.*;}</blockquote>
+ *
+ * Then one can choose a specific implementation by giving the name of a generator
+ * algorithm to the static method {@link RandomGenerator#of}, in which case the
+ * no-arguments constructor for that implementation is used:
+ *
+ * <blockquote>{@code RandomGenerator g = RandomGenerator.of("L64X128MixRandom");}</blockquote>
+ *
+ * For a single-threaded application, this is all that is needed. One can then
+ * invoke methods of {@code g} such as
+ * {@link RandomGenerator#nextLong nextLong()},
+ * {@link RandomGenerator#nextInt nextInt()},
+ * {@link RandomGenerator#nextFloat nextFloat()},
+ * {@link RandomGenerator#nextDouble nextDouble()} and
+ * {@link RandomGenerator#nextBoolean nextBoolean()} to generate individual
+ * randomly chosen values. One can also use the methods
+ * {@link RandomGenerator#ints ints()}, {@link RandomGenerator#longs longs()}
+ * and {@link RandomGenerator#doubles doubles()} to create streams of randomly
+ * chosen values. The methods
+ * {@link RandomGenerator#nextGaussian nextGaussian()} and
+ * {@link RandomGenerator#nextExponential nextExponential()} draw floating-point
+ * values from nonuniform distributions.
+ *
+ * <p> For a multi-threaded application, one can repeat the preceding steps
+ * to create additional {@linkplain RandomGenerator RandomGenerators}, but
+ * often it is preferable to use methods of the one single initially
+ * created generator to create others like it. (One reason is that some
+ * generator algorithms, if asked to create a new set of generators all at
+ * once, can make a special effort to ensure that the new generators are
+ * statistically independent.) If the initial generator implements the
+ * interface {@link RandomGenerator.StreamableGenerator}, then the method
+ * {@link RandomGenerator.StreamableGenerator#rngs rngs()} can be used to
+ * create a stream of generators. If this is a parallel stream, then it is
+ * easy to get parallel execution by using the
+ * {@link java.util.stream.Stream#map map()} method on the stream.
+ * <p> For a multi-threaded application that forks new threads dynamically,
+ * another approach is to use an initial generator that implements the interface
+ * {@link RandomGenerator.SplittableGenerator}, which is then considered to
+ * "belong" to the initial thread for its exclusive use; then whenever any
+ * thread needs to fork a new thread, it first uses the
+ * {@link RandomGenerator.SplittableGenerator#split split()} method of its own
+ * generator to create a new generator, which is then passed to the newly
+ * created thread for exclusive use by that new thread.
+ *
+ *
+ * <h2>Choosing a Random Number Generator Algorithm</h2>
+ *
+ * <p> There are three groups of random number generator algorithm provided
+ * in Java: the Legacy group, the LXM group, and the Xoroshiro/Xoshiro group.
+ *
+ * <p> The legacy group includes random number generators that existed
+ * before JDK 17: Random, ThreadLocalRandom, SplittableRandom, and
+ * SecureRandom. Random (LCG) is the weakest of the available algorithms, and it
+ * is recommended that users migrate to newer algorithms. If an application
+ * requires a random number generator algorithm that is cryptographically
+ * secure, then it should continue to use an instance of the class {@link
+ * java.security.SecureRandom}.
+ *
+ * <p> The algorithms in the LXM group are similar to each other. The parameters
+ * of each algorithm can be found in the algorithm name. The number after "L" indicates the
+ * number of state bits for the LCG subgenerator, and the number after "X" indicates the
+ * number of state bits for the XBG subgenerator. "Mix" indicates that
+ * the algorithm uses an 8-operation bit-mixing function; "StarStar" indicates use
+ * of a 3-operation bit-scrambler.
+ *
+ * <p> The algorithms in the Xoroshiro/Xoshiro group are more traditional algorithms
+ * (see David Blackman and Sebastiano Vigna, "Scrambled Linear Pseudorandom
+ * Number Generators," ACM Transactions on Mathematical Software, 2021);
+ * the number in the name indicates the number of state bits.
+ *
+ * <p> For applications (such as physical simulation, machine learning, and
+ * games) that do not require a cryptographically secure algorithm, this package
+ * provides multiple implementations of interface {@link RandomGenerator} that
+ * provide trade-offs among speed, space, period, accidental correlation, and
+ * equidistribution properties.
+ *
+ * <p> For applications with no special requirements,
+ * {@code L64X128MixRandom} has a good balance among speed, space,
+ * and period, and is suitable for both single-threaded and multi-threaded
+ * applications when used properly (a separate instance for each thread).
+ *
+ * <p> If the application uses only a single thread, then
+ * {@code Xoroshiro128PlusPlus} is even smaller and faster, and
+ * certainly has a sufficiently long period.
+ *
+ * <p> For an application running in a 32-bit hardware environment and using
+ * only one thread or a small number of threads, {@code L32X64MixRandom} may be a good
+ * choice.
+ *
+ * <p> For an application that uses many threads that are allocated in one batch
+ * at the start of the computation, either a "jumpable" generator such as
+ * {@code Xoroshiro128PlusPlus} or
+ * {@code Xoshiro256PlusPlus} may be used, or a "splittable"
+ * generator such as {@code L64X128MixRandom} or
+ * {@code L64X256MixRandom} may be used.
+ *
+ * <p> For an application that creates many threads dynamically, perhaps through
+ * the use of spliterators, a "splittable" generator such as
+ * {@code L64X128MixRandom} or {@code L64X256MixRandom} is
+ * recommended. If the number of generators created dynamically may
+ * be very large (millions or more), then using generators such as
+ * {@code L128X128MixRandom} or {@code L128X256MixRandom},
+ * which use a 128-bit parameter rather than a 64-bit parameter for their LCG
+ * subgenerator, will make it much less likely that two instances use the same
+ * state cycle.
+ *
+ * <p> For an application that uses tuples of consecutively generated values, it
+ * may be desirable to use a generator that is <i>k</i>-equidistributed such
+ * that <i>k</i> is at least as large as the length of the tuples being
+ * generated. The generator {@code L64X256MixRandom} is provably
+ * 4-equidistributed, and {@code L64X1024MixRandom} is provably
+ * 16-equidistributed.
+ *
+ * <p> For applications that generate large permutations, it may be best to use
+ * a generator whose period is much larger than the total number of possible
+ * permutations; otherwise it will be impossible to generate some of the
+ * intended permutations. For example, if the goal is to shuffle a deck of 52
+ * cards, the number of possible permutations is 52! (52 factorial), which is
+ * larger than 2<sup>225</sup> (but smaller than 2<sup>226</sup>), so it may be
+ * best to use a generator whose period at least 2<sup>256</sup>, such as
+ * {@code L64X256MixRandom} or {@code L64X1024MixRandom}
+ * or {@code L128X256MixRandom} or
+ * {@code L128X1024MixRandom}. (It is of course also necessary to
+ * provide sufficiently many seed bits when the generator is initialized, or
+ * else it will still be impossible to generate some of the intended
+ * permutations.)
+ *
+ *
+ * <h2><a id="algorithms">Random Number Generator Algorithms Available</a></h2>
+ *
+ * These algorithms [in the table below] must be found with the current version
+ * of Java SE. A particular JDK implementation may recognize additional
+ * algorithms; check the JDK's documentation for details. The set of algorithms
+ * required by Java SE may be updated by changes to the Java SE specification.
+ * Over time, new algorithms may be added and old algorithms may be removed.
+ * <p>In addition, as another life-cycle phase, an algorithm may be {@linkplain
+ * RandomGeneratorFactory#isDeprecated() deprecated}. A deprecated algorithm is
+ * not recommended for use. If a required algorithm is deprecated, it may be
+ * removed in a future release. Due to advances in random number generator
+ * algorithm development and analysis, an algorithm may be deprecated during the
+ * lifetime of a particular Java SE release. Changing the deprecation status of
+ * an algorithm is <em>not</em> a specification change.
+ *
+ * <table style="padding:0px 20px 0px 0px">
+ *  <caption>Available Algorithms</caption>
+ *  <thead>
+ *  <tr>
+ *      <th style="text-align:left">Algorithm</th>
+ *      <th style="text-align:left">Group</th>
+ *      <th style="text-align:left">Period</th>
+ *      <th style="text-align:right">StateBits</th>
+ *      <th style="text-align:right">Equidistribution</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *      <td style="text-align:left">L128X1024MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(1024).subtract(BigInteger.ONE).shiftLeft(128)</td>
+ *      <td style="text-align:right">1152</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L128X128MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE).shiftLeft(128)</td>
+ *      <td style="text-align:right">256</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L128X256MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE).shiftLeft(128)</td>
+ *      <td style="text-align:right">384</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L32X64MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE).shiftLeft(32)</td>
+ *      <td style="text-align:right">96</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L64X1024MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(1024).subtract(BigInteger.ONE).shiftLeft(64)</td>
+ *      <td style="text-align:right">1088</td>
+ *      <td style="text-align:right">16</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L64X128MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE).shiftLeft(64)</td>
+ *      <td style="text-align:right">192</td>
+ *      <td style="text-align:right">2</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L64X128StarStarRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE).shiftLeft(64)</td>
+ *      <td style="text-align:right">192</td>
+ *      <td style="text-align:right">2</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">L64X256MixRandom</td>
+ *      <td style="text-align:left">LXM</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE).shiftLeft(64)</td>
+ *      <td style="text-align:right">320</td>
+ *      <td style="text-align:right">4</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">Random</td>
+ *      <td style="text-align:left">Legacy</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(48)</td>
+ *      <td style="text-align:right">48</td>
+ *      <td style="text-align:right">0</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">SplittableRandom</td>
+ *      <td style="text-align:left">Legacy</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(64)</td>
+ *      <td style="text-align:right">64</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">ThreadLocalRandom <sup>*</sup></td>
+ *      <td style="text-align:left">Legacy</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(64)</td>
+ *      <td style="text-align:right">64</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">Xoroshiro128PlusPlus</td>
+ *      <td style="text-align:left">Xoroshiro</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE)</td>
+ *      <td style="text-align:right">128</td>
+ *      <td style="text-align:right">1</td>
+ *  </tr>
+ *  <tr>
+ *      <td style="text-align:left">Xoshiro256PlusPlus</td>
+ *      <td style="text-align:left">Xoshiro</td>
+ *      <td style="text-align:left">BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE)</td>
+ *      <td style="text-align:right">256</td>
+ *      <td style="text-align:right">3</td>
+ *  </tr>
+ *  </tbody>
+ * </table>
+ *
+ * <p><sup>*</sup> ThreadLocalRandom can only be accessed via
+ * {@link java.util.concurrent.ThreadLocalRandom#current()}.
+ *
+ * <h2>Categories of Random Number Generator Algorithms</h2>
+ *
+ * Historically, most pseudorandom generator algorithms have been based on some
+ * sort of finite-state machine with a single, large cycle of states; when it is
+ * necessary to have multiple threads use the same algorithm simultaneously, the
+ * usual technique is to arrange for each thread to traverse a different region
+ * of the state cycle. These regions may be doled out to threads by starting
+ * with a single initial state and then using a "jump function" that travels a
+ * long distance around the cycle (perhaps 2<sup>64</sup> steps or more); the
+ * jump function is applied repeatedly and sequentially, to identify widely
+ * spaced states that are then doled out, one to each thread, to serve as the
+ * initial state for the generator to be used by that thread. This strategy is
+ * supported by the interface {@link RandomGenerator.JumpableGenerator}.
+ * Sometimes it is desirable to support two levels of jumping (by long distances
+ * and by <i>really</i> long distances); this strategy is supported by the
+ * interface {@link RandomGenerator.LeapableGenerator}. There is also an interface
+ * {@link RandomGenerator.ArbitrarilyJumpableGenerator} for algorithms that allow
+ * jumping along the state cycle by any user-specified distance. In this package,
+ * implementations of these interfaces include
+ * "Xoroshiro128PlusPlus", and
+ * "Xoshiro256PlusPlus".
+ *
+ * <p> A more recent category of "splittable" pseudorandom generator algorithms
+ * uses a large family of state cycles and makes some attempt to ensure that
+ * distinct instances use different state cycles; but even if two instances
+ * "accidentally" use the same state cycle, they are highly likely to traverse
+ * different regions parts of that shared state cycle. This strategy is
+ * supported by the interface {@link RandomGenerator.SplittableGenerator}.
+ * In this package, implementations of this interface include
+ * "L32X64MixRandom",
+ * "L64X128StarStarRandom",
+ * "L64X128MixRandom",
+ * "L64X256MixRandom",
+ * "L64X1024MixRandom",
+ * "L128X128MixRandom",
+ * "L128X256MixRandom", and
+ * "L128X1024MixRandom"; note that the class
+ * {@link java.util.SplittableRandom} also implements this interface.
+ *
+ *
+ * <h2>The LXM Family of Random Number Generator Algorithms</h2>
+ *
+ * The structure of the central nextLong (or nextInt) method of an LXM
+ * algorithm follows a suggestion in December 2017 by Sebastiano Vigna
+ * that using one Linear Congruential Generator (LCG) as a first subgenerator
+ * and one Xor-Based Generator (XBG) as a second subgenerator (rather
+ * than using two LCG subgenerators) would provide a longer period, superior
+ * equidistribution, scalability, and better quality.  Each of the
+ * specific implementations here combines one of the best currently known
+ * XBG algorithms (xoroshiro128 or xoshiro256, described by Blackman and
+ * Vigna in "Scrambled Linear Pseudorandom Number Generators", ACM Transactions
+ * on Mathematical Software, 2021) with an LCG that uses one of the best
+ * currently known multipliers (found by a search for better multipliers
+ * in 2019 by Steele and Vigna), and then applies either a mixing function
+ * identified by Doug Lea or a simple scrambler proposed by Blackman and Vigna.
+ * Testing has confirmed that the LXM algorithm is far superior in quality to
+ * the SplitMix algorithm (2014) used by {@code SplittableRandom}.
+ *
+ * Each class with a name of the form
+ * {@code L}<i>p</i>{@code X}<i>q</i>{@code SomethingRandom}
+ * uses some specific member of the LXM family of random number
+ * algorithms; "LXM" is short for "LCG, XBG, Mixer". Every LXM
+ * generator has two subgenerators; one is an LCG (Linear Congruential
+ * Generator) and the other is an XBG (Xor-Based Generator). Each output of an LXM
+ * generator is the result of combining state from the LCG with state from the
+ * XBG using a Mixing function (and then the state of the LCG
+ * and the state of the XBG are advanced).
+ *
+ * <p> The LCG subgenerator has an update step of the form {@code s = m*s + a},
+ * where {@code s}, {@code m}, and {@code a} are all binary integers of the same
+ * size, each having <i>p</i> bits; {@code s} is the mutable state, the
+ * multiplier {@code m} is fixed (the same for all instances of a class) and the
+ * addend {@code a} is a parameter (a final field of the instance). The
+ * parameter {@code a} is required to be odd (this allows the LCG to have the
+ * maximal period, namely 2<sup><i>p</i></sup>); therefore there are
+ * 2<sup><i>p</i>&minus;1</sup> distinct choices of parameter. (When the size of
+ * {@code s} is 128 bits, then we use the name "{@code sh}" below to refer to
+ * the high half of {@code s}, that is, the high-order 64 bits of {@code s}.)
+ *
+ * <p> The XBG subgenerator can in principle be any one of a wide variety
+ * of XBG algorithms; in this package it is always either
+ * {@code xoroshiro128}, {@code xoshiro256}, or {@code xoroshiro1024}, in each
+ * case without any final scrambler (such as "+" or "**") because LXM uses
+ * a separate Mixer later in the process. The XBG state consists of
+ * some fixed number of {@code int} or {@code long} fields, generally named
+ * {@code x0}, {@code x1}, and so on, which can take on any values provided that
+ * they are not all zero. The collective total size of these fields is <i>q</i>
+ * bits; therefore the period of this subgenerator is
+ * 2<sup><i>q</i></sup>&minus;1.
+ *
+ * <p> Because the periods 2<sup><i>p</i></sup> and 2<sup><i>q</i></sup>&minus;1
+ * of the two subgenerators are relatively prime, the <em>period</em> of any
+ * single instance of an LXM algorithm (the length of the series of generated
+ * values before it repeats) is the product of the periods of the subgenerators,
+ * that is, 2<sup><i>p</i></sup>(2<sup><i>q</i></sup>&minus;1), which is just
+ * slightly smaller than 2<sup>(<i>p</i>+<i>q</i>)</sup>. Moreover, if two
+ * distinct instances of the same LXM algorithm have different {@code a}
+ * parameters, then their cycles of produced values will be different.
+ *
+ * <p> Generally speaking, among the "{@code L}<i>p</i>{@code X}<i>q</i>"
+ * generators, the memory required for an instance is 2<i>p</i>+<i>q</i> bits.
+ * (If <i>q</i> is 1024 or larger, the XBG state is represented as an
+ * array, so additional bits are needed for the array object header, and another
+ * 32 bits are used for an array index.)
+ *
+ * <p> Larger values of <i>p</i> imply a lower probability that two distinct
+ * instances will traverse the same state cycle, and larger values of <i>q</i>
+ * imply that the generator is equidistributed in a larger number of dimensions
+ * (this is provably true when <i>p</i> is 64, and conjectured to be
+ * approximately true when <i>p</i> is 128). A class with "{@code Mix}" in its
+ * name uses a fairly strong mixing function with excellent avalanche
+ * characteristics; a class with "{@code StarStar}" in its name uses a weaker
+ * but faster mixing function.
+ *
+ * <p> The specific LXM algorithms used in this package are all chosen so that
+ * the 64-bit values produced by the {@link RandomGenerator#nextLong nextLong()}
+ * method are exactly equidistributed (for example, for any specific instance of
+ * "L64X128MixRandom", over the course of its cycle each of the
+ * 2<sup>64</sup> possible {@code long} values will be produced
+ * 2<sup>128</sup>&minus;1 times). The values produced by the
+ * {@link RandomGenerator#nextInt nextInt()},
+ * {@link RandomGenerator#nextFloat nextFloat()}, and
+ * {@link RandomGenerator#nextDouble nextDouble()} methods are likewise exactly
+ * equidistributed. Some algorithms provide a further guarantee of
+ * <i>k</i>-equidistribution for some <i>k</i> greater than 1, meaning that successive
+ * non-overlapping <i>k</i>-tuples of 64-bit values produced by the
+ * {@link RandomGenerator#nextLong nextLong()} method are exactly
+ * equidistributed (equally likely to occur).
+ *
+ * <p> The following table gives the period, state size (in bits), parameter
+ * size (in bits, including the low-order bit that is required always to be a
+ * 1-bit), and equidistribution property for each of the specific LXM algorithms
+ * used in this package.
+ *
+ * <table style="padding:0px 20px 0px 0px">
+ * <caption>Algorithm Properties</caption>
+ * <thead>
+ *   <tr><th style="text-align:left">Implementation</th>
+ *       <th style="text-align:right">Period</th>
+ *       <th style="text-align:right">State size</th>
+ *       <th style="text-align:right">Parameter size</th>
+ *       <th style="text-align:left">{@link RandomGenerator#nextLong nextLong()} values are</th></tr>
+ * </thead>
+ * <tbody>
+ *   <tr><td style="text-align:left">"L32X64MixRandom"</td>
+ *       <td style="text-align:right">2<sup>32</sup>(2<sup>64</sup>&minus;1)</td>
+ *       <td style="text-align:right">96 bits</td>
+ *       <td style="text-align:right">32 bits</td>
+ *       <td style="text-align:left"></td></tr>
+ *   <tr><td style="text-align:left">"L64X128StarStarRandom"</td>
+ *       <td style="text-align:right">2<sup>64</sup>(2<sup>128</sup>&minus;1)</td>
+ *       <td style="text-align:right">192 bits</td>
+ *       <td style="text-align:right">64 bits</td>
+ *       <td style="text-align:left">2-equidistributed and exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L64X128MixRandom"</td>
+ *       <td style="text-align:right">2<sup>64</sup>(2<sup>128</sup>&minus;1)</td>
+ *       <td style="text-align:right">192 bits</td>
+ *       <td style="text-align:right">64 bits</td>
+ *       <td style="text-align:left">2-equidistributed and exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L64X256MixRandom"</td>
+ *       <td style="text-align:right">2<sup>64</sup>(2<sup>256</sup>&minus;1)</td>
+ *       <td style="text-align:right">320 bits</td>
+ *       <td style="text-align:right">64 bits</td>
+ *       <td style="text-align:left">4-equidistributed and exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L64X1024MixRandom"</td>
+ *       <td style="text-align:right">2<sup>64</sup>(2<sup>1024</sup>&minus;1)</td>
+ *       <td style="text-align:right">1088 bits</td>
+ *       <td style="text-align:right">64 bits</td>
+ *       <td style="text-align:left">16-equidistributed and exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L128X128MixRandom"</td>
+ *       <td style="text-align:right">2<sup>128</sup>(2<sup>128</sup>&minus;1)</td>
+ *       <td style="text-align:right">256 bits</td>
+ *       <td style="text-align:right">128 bits</td>
+ *       <td style="text-align:left">exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L128X256MixRandom"</td>
+ *       <td style="text-align:right">2<sup>128</sup>(2<sup>256</sup>&minus;1)</td>
+ *       <td style="text-align:right">384 bits</td>
+ *       <td style="text-align:right">128 bits</td>
+ *       <td style="text-align:left">exactly equidistributed</td></tr>
+ *   <tr><td style="text-align:left">"L128X1024MixRandom"</td>
+ *       <td style="text-align:right">2<sup>128</sup>(2<sup>1024</sup>&minus;1)</td>
+ *       <td style="text-align:right">1152 bits</td>
+ *       <td style="text-align:right">128 bits</td>
+ *       <td style="text-align:left">exactly equidistributed</td></tr>
+ * </tbody>
+ * </table>
+ *
+ * For the algorithms listed above whose names begin with {@code L32}, the
+ * 32-bit values produced by the {@link RandomGenerator#nextInt nextInt()}
+ * method are exactly equidistributed, but the 64-bit values produced by the
+ * {@link RandomGenerator#nextLong nextLong()} method are not exactly
+ * equidistributed.
+ *
+ * <p> For the algorithms listed above whose names begin with {@code L64} or
+ * {@code L128}, the 64-bit values produced by the
+ * {@link RandomGenerator#nextLong nextLong()} method are <i>exactly
+ * equidistributed</i>: every instance, over the course of its cycle, will
+ * produce each of the 2<sup>64</sup> possible {@code long} values exactly the
+ * same number of times. For example, any specific instance of
+ * "L64X256MixRandom", over the course of its cycle each of the
+ * 2<sup>64</sup> possible {@code long} values will be produced
+ * 2<sup>256</sup>&minus;1 times. The values produced by the
+ * {@link RandomGenerator#nextInt nextInt()},
+ * {@link RandomGenerator#nextFloat nextFloat()}, and
+ * {@link RandomGenerator#nextDouble nextDouble()} methods are likewise exactly
+ * equidistributed.
+ *
+ * <p> In addition, for the algorithms listed above whose names begin with
+ * {@code L64}, the 64-bit values produced by the
+ * {@link RandomGenerator#nextLong nextLong()} method are
+ * <i>k</i>-equidistributed (but not exactly <i>k</i>-equidistributed). To be
+ * precise, and taking "L64X256MixRandom" as an example: for
+ * any specific instance of "L64X256MixRandom", consider the
+ * (overlapping) length-4 subsequences of the cycle of 64-bit values produced by
+ * {@link RandomGenerator#nextLong nextLong()} (assuming no other methods are
+ * called that would affect the state). There are
+ * 2<sup>64</sup>(2<sup>256</sup>&minus;1) such subsequences, and each
+ * subsequence, which consists of 4 64-bit values, can have one of
+ * 2<sup>256</sup> values. Of those 2<sup>256</sup> subsequence values, nearly
+ * all of them (2<sup>256</sup>&minus;2<sup>64</sup>) occur 2<sup>64</sup> times
+ * over the course of the entire cycle, and the other 2<sup>64</sup> subsequence
+ * values occur only 2<sup>64</sup>&minus;1 times. So the ratio of the
+ * probability of getting any specific one of the less common subsequence values
+ * and the probability of getting any specific one of the more common
+ * subsequence values is 1&minus;2<sup>-64</sup>. (Note that the set of
+ * 2<sup>64</sup> less-common subsequence values will differ from one instance
+ * of "L64X256MixRandom" to another, as a function of the
+ * additive parameter of the LCG.) The values produced by the
+ * {@link RandomGenerator#nextInt nextInt()},
+ * {@link RandomGenerator#nextFloat nextFloat()}, and
+ * {@link RandomGenerator#nextDouble nextDouble()} methods are likewise
+ * 4-equidistributed (but not exactly 4-equidistributed).
+ *
+ * <p> The next table gives the LCG multiplier value, the name of the specific
+ * XBG algorithm used, the specific numeric parameters for that XBG
+ * algorithm, and the mixing function for each of the specific LXM algorithms
+ * used in this package. (Note that the multiplier used for the 128-bit LCG
+ * cases is 65 bits wide, so the constant {@code 0x1d605bbb58c8abbfdL} shown in
+ * the table cannot actually be used in code; instead, only the 64 low-order
+ * bits {@code 0xd605bbb58c8abbfdL} are represented in the source code, and the
+ * missing 1-bit is handled through special coding of the multiply-add algorithm
+ * used in the LCG.)
+ *
+ * <table style="padding:0px 20px 0px 0px">
+ * <caption>LXM Multipliers</caption>
+ * <thead>
+ *   <tr><th style="text-align:left">Implementation</th>
+ *       <th style="text-align:right">LCG multiplier {@code m}</th>
+ *       <th style="text-align:left">XBG algorithm</th>
+ *       <th style="text-align:left">XBG parameters</th>
+ *       <th style="text-align:left">Mixing function</th></tr>
+ * </thead>
+ * <tbody>
+ *   <tr><td style="text-align:left">"L32X64MixRandom"</td>
+ *       <td style="text-align:right">{@code 0xadb4a92d}</td>
+ *       <td style="text-align:left">{@code xoroshiro64}, version 1.0</td>
+ *       <td style="text-align:left">{@code (26, 9, 13)}</td>
+ *       <td style="text-align:left">mixLea32{@code (s+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L64X128StarStarRandom" </td>
+ *       <td style="text-align:right">{@code 0xd1342543de82ef95L}</td>
+ *       <td style="text-align:left">{@code xoroshiro128}, version 1.0</td>
+ *       <td style="text-align:left">{@code (24, 16, 37)}</td>
+ *       <td style="text-align:left">{@code Long.rotateLeft((s+x0)* 5, 7) * 9}</td></tr>
+ *   <tr><td style="text-align:left">"L64X128MixRandom"</td>
+ *       <td style="text-align:right">{@code 0xd1342543de82ef95L}</td>
+ *       <td style="text-align:left">{@code xoroshiro128}, version 1.0</td>
+ *       <td style="text-align:left">{@code (24, 16, 37)}</td>
+ *       <td style="text-align:left">mixLea64{@code (s+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L64X256MixRandom"</td>
+ *       <td style="text-align:right">{@code 0xd1342543de82ef95L}</td>
+ *       <td style="text-align:left">{@code xoshiro256}, version 1.0</td>
+ *       <td style="text-align:left">{@code (17, 45)}</td>
+ *       <td style="text-align:left">mixLea64{@code (s+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L64X1024MixRandom"</td>
+ *       <td style="text-align:right">{@code 0xd1342543de82ef95L}</td>
+ *       <td style="text-align:left">{@code xoroshiro1024}, version 1.0</td>
+ *       <td style="text-align:left">{@code (25, 27, 36)}</td>
+ *       <td style="text-align:left">mixLea64{@code (s+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L128X128MixRandom"</td>
+ *       <td style="text-align:right">{@code 0x1d605bbb58c8abbfdL}</td>
+ *       <td style="text-align:left">{@code xoroshiro128}, version 1.0</td>
+ *       <td style="text-align:left">{@code (24, 16, 37)}</td>
+ *       <td style="text-align:left">mixLea64{@code (sh+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L128X256MixRandom"</td>
+ *       <td style="text-align:right">{@code 0x1d605bbb58c8abbfdL}</td>
+ *       <td style="text-align:left">{@code xoshiro256}, version 1.0</td>
+ *       <td style="text-align:left">{@code (17, 45)}</td>
+ *       <td style="text-align:left">mixLea64{@code (sh+x0)}</td></tr>
+ *   <tr><td style="text-align:left">"L128X1024MixRandom"</td>
+ *       <td style="text-align:right">{@code 0x1d605bbb58c8abbfdL}</td>
+ *       <td style="text-align:left">{@code xoroshiro1024}, version 1.0</td>
+ *       <td style="text-align:left">{@code (25, 27, 36)}</td>
+ *       <td style="text-align:left">mixLea64{@code (sh+x0)}</td></tr>
+ * </tbody>
+ * </table>
+ *
+ * @since   17
+ */
+package java.util.random;
+
diff --git a/android-35/java/util/regex/ASCII.java b/android-35/java/util/regex/ASCII.java
new file mode 100644
index 0000000..a50fa98
--- /dev/null
+++ b/android-35/java/util/regex/ASCII.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+
+/**
+ * Utility class that implements the standard C ctype functionality.
+ *
+ * @author Hong Zhang
+ */
+
+final class ASCII {
+
+    static final int UPPER   = 0x00000100;
+
+    static final int LOWER   = 0x00000200;
+
+    static final int DIGIT   = 0x00000400;
+
+    static final int SPACE   = 0x00000800;
+
+    static final int PUNCT   = 0x00001000;
+
+    static final int CNTRL   = 0x00002000;
+
+    static final int BLANK   = 0x00004000;
+
+    static final int HEX     = 0x00008000;
+
+    static final int UNDER   = 0x00010000;
+
+    static final int ASCII   = 0x0000FF00;
+
+    static final int ALPHA   = (UPPER|LOWER);
+
+    static final int ALNUM   = (UPPER|LOWER|DIGIT);
+
+    static final int GRAPH   = (PUNCT|UPPER|LOWER|DIGIT);
+
+    static final int WORD    = (UPPER|LOWER|UNDER|DIGIT);
+
+    static final int XDIGIT  = (HEX);
+
+    private static final int[] ctype = new int[] {
+        CNTRL,                  /* 00 (NUL) */
+        CNTRL,                  /* 01 (SOH) */
+        CNTRL,                  /* 02 (STX) */
+        CNTRL,                  /* 03 (ETX) */
+        CNTRL,                  /* 04 (EOT) */
+        CNTRL,                  /* 05 (ENQ) */
+        CNTRL,                  /* 06 (ACK) */
+        CNTRL,                  /* 07 (BEL) */
+        CNTRL,                  /* 08 (BS)  */
+        SPACE+CNTRL+BLANK,      /* 09 (HT)  */
+        SPACE+CNTRL,            /* 0A (LF)  */
+        SPACE+CNTRL,            /* 0B (VT)  */
+        SPACE+CNTRL,            /* 0C (FF)  */
+        SPACE+CNTRL,            /* 0D (CR)  */
+        CNTRL,                  /* 0E (SI)  */
+        CNTRL,                  /* 0F (SO)  */
+        CNTRL,                  /* 10 (DLE) */
+        CNTRL,                  /* 11 (DC1) */
+        CNTRL,                  /* 12 (DC2) */
+        CNTRL,                  /* 13 (DC3) */
+        CNTRL,                  /* 14 (DC4) */
+        CNTRL,                  /* 15 (NAK) */
+        CNTRL,                  /* 16 (SYN) */
+        CNTRL,                  /* 17 (ETB) */
+        CNTRL,                  /* 18 (CAN) */
+        CNTRL,                  /* 19 (EM)  */
+        CNTRL,                  /* 1A (SUB) */
+        CNTRL,                  /* 1B (ESC) */
+        CNTRL,                  /* 1C (FS)  */
+        CNTRL,                  /* 1D (GS)  */
+        CNTRL,                  /* 1E (RS)  */
+        CNTRL,                  /* 1F (US)  */
+        SPACE+BLANK,            /* 20 SPACE */
+        PUNCT,                  /* 21 !     */
+        PUNCT,                  /* 22 "     */
+        PUNCT,                  /* 23 #     */
+        PUNCT,                  /* 24 $     */
+        PUNCT,                  /* 25 %     */
+        PUNCT,                  /* 26 &     */
+        PUNCT,                  /* 27 '     */
+        PUNCT,                  /* 28 (     */
+        PUNCT,                  /* 29 )     */
+        PUNCT,                  /* 2A *     */
+        PUNCT,                  /* 2B +     */
+        PUNCT,                  /* 2C ,     */
+        PUNCT,                  /* 2D -     */
+        PUNCT,                  /* 2E .     */
+        PUNCT,                  /* 2F /     */
+        DIGIT+HEX+0,            /* 30 0     */
+        DIGIT+HEX+1,            /* 31 1     */
+        DIGIT+HEX+2,            /* 32 2     */
+        DIGIT+HEX+3,            /* 33 3     */
+        DIGIT+HEX+4,            /* 34 4     */
+        DIGIT+HEX+5,            /* 35 5     */
+        DIGIT+HEX+6,            /* 36 6     */
+        DIGIT+HEX+7,            /* 37 7     */
+        DIGIT+HEX+8,            /* 38 8     */
+        DIGIT+HEX+9,            /* 39 9     */
+        PUNCT,                  /* 3A :     */
+        PUNCT,                  /* 3B ;     */
+        PUNCT,                  /* 3C <     */
+        PUNCT,                  /* 3D =     */
+        PUNCT,                  /* 3E >     */
+        PUNCT,                  /* 3F ?     */
+        PUNCT,                  /* 40 @     */
+        UPPER+HEX+10,           /* 41 A     */
+        UPPER+HEX+11,           /* 42 B     */
+        UPPER+HEX+12,           /* 43 C     */
+        UPPER+HEX+13,           /* 44 D     */
+        UPPER+HEX+14,           /* 45 E     */
+        UPPER+HEX+15,           /* 46 F     */
+        UPPER+16,               /* 47 G     */
+        UPPER+17,               /* 48 H     */
+        UPPER+18,               /* 49 I     */
+        UPPER+19,               /* 4A J     */
+        UPPER+20,               /* 4B K     */
+        UPPER+21,               /* 4C L     */
+        UPPER+22,               /* 4D M     */
+        UPPER+23,               /* 4E N     */
+        UPPER+24,               /* 4F O     */
+        UPPER+25,               /* 50 P     */
+        UPPER+26,               /* 51 Q     */
+        UPPER+27,               /* 52 R     */
+        UPPER+28,               /* 53 S     */
+        UPPER+29,               /* 54 T     */
+        UPPER+30,               /* 55 U     */
+        UPPER+31,               /* 56 V     */
+        UPPER+32,               /* 57 W     */
+        UPPER+33,               /* 58 X     */
+        UPPER+34,               /* 59 Y     */
+        UPPER+35,               /* 5A Z     */
+        PUNCT,                  /* 5B [     */
+        PUNCT,                  /* 5C \     */
+        PUNCT,                  /* 5D ]     */
+        PUNCT,                  /* 5E ^     */
+        PUNCT|UNDER,            /* 5F _     */
+        PUNCT,                  /* 60 `     */
+        LOWER+HEX+10,           /* 61 a     */
+        LOWER+HEX+11,           /* 62 b     */
+        LOWER+HEX+12,           /* 63 c     */
+        LOWER+HEX+13,           /* 64 d     */
+        LOWER+HEX+14,           /* 65 e     */
+        LOWER+HEX+15,           /* 66 f     */
+        LOWER+16,               /* 67 g     */
+        LOWER+17,               /* 68 h     */
+        LOWER+18,               /* 69 i     */
+        LOWER+19,               /* 6A j     */
+        LOWER+20,               /* 6B k     */
+        LOWER+21,               /* 6C l     */
+        LOWER+22,               /* 6D m     */
+        LOWER+23,               /* 6E n     */
+        LOWER+24,               /* 6F o     */
+        LOWER+25,               /* 70 p     */
+        LOWER+26,               /* 71 q     */
+        LOWER+27,               /* 72 r     */
+        LOWER+28,               /* 73 s     */
+        LOWER+29,               /* 74 t     */
+        LOWER+30,               /* 75 u     */
+        LOWER+31,               /* 76 v     */
+        LOWER+32,               /* 77 w     */
+        LOWER+33,               /* 78 x     */
+        LOWER+34,               /* 79 y     */
+        LOWER+35,               /* 7A z     */
+        PUNCT,                  /* 7B {     */
+        PUNCT,                  /* 7C |     */
+        PUNCT,                  /* 7D }     */
+        PUNCT,                  /* 7E ~     */
+        CNTRL,                  /* 7F (DEL) */
+    };
+
+    static int getType(int ch) {
+        return ((ch & 0xFFFFFF80) == 0 ? ctype[ch] : 0);
+    }
+
+    static boolean isType(int ch, int type) {
+        return (getType(ch) & type) != 0;
+    }
+
+    static boolean isAscii(int ch) {
+        return ((ch & 0xFFFFFF80) == 0);
+    }
+
+    static boolean isAlpha(int ch) {
+        return isType(ch, ALPHA);
+    }
+
+    static boolean isDigit(int ch) {
+        return ((ch-'0')|('9'-ch)) >= 0;
+    }
+
+    static boolean isAlnum(int ch) {
+        return isType(ch, ALNUM);
+    }
+
+    static boolean isGraph(int ch) {
+        return isType(ch, GRAPH);
+    }
+
+    static boolean isPrint(int ch) {
+        return ((ch-0x20)|(0x7E-ch)) >= 0;
+    }
+
+    static boolean isPunct(int ch) {
+        return isType(ch, PUNCT);
+    }
+
+    static boolean isSpace(int ch) {
+        return isType(ch, SPACE);
+    }
+
+    static boolean isHexDigit(int ch) {
+        return isType(ch, HEX);
+    }
+
+    static boolean isOctDigit(int ch) {
+        return ((ch-'0')|('7'-ch)) >= 0;
+    }
+
+    static boolean isCntrl(int ch) {
+        return isType(ch, CNTRL);
+    }
+
+    static boolean isLower(int ch) {
+        return ((ch-'a')|('z'-ch)) >= 0;
+    }
+
+    static boolean isUpper(int ch) {
+        return ((ch-'A')|('Z'-ch)) >= 0;
+    }
+
+    static boolean isWord(int ch) {
+        return isType(ch, WORD);
+    }
+
+    static int toDigit(int ch) {
+        return (ctype[ch & 0x7F] & 0x3F);
+    }
+
+    static int toLower(int ch) {
+        return isUpper(ch) ? (ch + 0x20) : ch;
+    }
+
+    static int toUpper(int ch) {
+        return isLower(ch) ? (ch - 0x20) : ch;
+    }
+
+}
diff --git a/android-35/java/util/regex/MatchResult.java b/android-35/java/util/regex/MatchResult.java
new file mode 100644
index 0000000..1e69638
--- /dev/null
+++ b/android-35/java/util/regex/MatchResult.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+/**
+ * The result of a match operation.
+ *
+ * <p>This interface contains query methods used to determine the
+ * results of a match against a regular expression. The match boundaries,
+ * groups and group boundaries can be seen but not modified through
+ * a {@code MatchResult}.
+ *
+ * @author  Michael McCloskey
+ * @see Matcher
+ * @since 1.5
+ */
+public interface MatchResult {
+
+    /**
+     * Returns the start index of the match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start();
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i>{@code start(0)} is equivalent to
+     * <i>m.</i>{@code start()}.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or {@code -1} if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group);
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end();
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i>{@code end(0)} is equivalent to
+     * <i>m.</i>{@code end()}.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or {@code -1} if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group);
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i>{@code group()} and
+     * <i>s.</i>{@code substring(}<i>m.</i>{@code start(),}&nbsp;<i>m.</i>{@code end())}
+     * are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example {@code a*}, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group();
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i>{@code group(}<i>g</i>{@code )} and
+     * <i>s.</i>{@code substring(}<i>m.</i>{@code start(}<i>g</i>{@code
+     * ),}&nbsp;<i>m.</i>{@code end(}<i>g</i>{@code ))}
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression {@code m.group(0)} is equivalent to {@code m.group()}.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then {@code null} is returned. Note
+     * that some groups, for example {@code (a*)}, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or {@code null} if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group);
+
+    /**
+     * Returns the number of capturing groups in this match result's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount();
+
+}
diff --git a/android-35/java/util/regex/Matcher.java b/android-35/java/util/regex/Matcher.java
new file mode 100644
index 0000000..2f8ea4c
--- /dev/null
+++ b/android-35/java/util/regex/Matcher.java
@@ -0,0 +1,1855 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import com.android.icu.util.regex.MatcherNative;
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * An engine that performs match operations on a {@linkplain
+ * java.lang.CharSequence character sequence} by interpreting a {@link Pattern}.
+ *
+ * <p> A matcher is created from a pattern by invoking the pattern's {@link
+ * Pattern#matcher matcher} method.  Once created, a matcher can be used to
+ * perform three different kinds of match operations:
+ *
+ * <ul>
+ *
+ *   <li><p> The {@link #matches matches} method attempts to match the entire
+ *   input sequence against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #lookingAt lookingAt} method attempts to match the
+ *   input sequence, starting at the beginning, against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #find find} method scans the input sequence looking
+ *   for the next subsequence that matches the pattern.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Each of these methods returns a boolean indicating success or failure.
+ * More information about a successful match can be obtained by querying the
+ * state of the matcher.
+ *
+ * <p> A matcher finds matches in a subset of its input called the
+ * <i>region</i>. By default, the region contains all of the matcher's input.
+ * The region can be modified via the {@link #region(int, int) region} method
+ * and queried via the {@link #regionStart() regionStart} and {@link
+ * #regionEnd() regionEnd} methods. The way that the region boundaries interact
+ * with some pattern constructs can be changed. See {@link
+ * #useAnchoringBounds(boolean) useAnchoringBounds} and {@link
+ * #useTransparentBounds(boolean) useTransparentBounds} for more details.
+ *
+ * <p> This class also defines methods for replacing matched subsequences with
+ * new strings whose contents can, if desired, be computed from the match
+ * result.  The {@link #appendReplacement appendReplacement} and {@link
+ * #appendTail appendTail} methods can be used in tandem in order to collect
+ * the result into an existing string buffer or string builder. Alternatively,
+ * the more convenient {@link #replaceAll replaceAll} method can be used to
+ * create a string in which every matching subsequence in the input sequence
+ * is replaced.
+ *
+ * <p> The explicit state of a matcher includes the start and end indices of
+ * the most recent successful match.  It also includes the start and end
+ * indices of the input subsequence captured by each <a
+ * href="Pattern.html#cg">capturing group</a> in the pattern as well as a total
+ * count of such subsequences.  As a convenience, methods are also provided for
+ * returning these captured subsequences in string form.
+ *
+ * <p> The explicit state of a matcher is initially undefined; attempting to
+ * query any part of it before a successful match will cause an {@link
+ * IllegalStateException} to be thrown.  The explicit state of a matcher is
+ * recomputed by every match operation.
+ *
+ * <p> The implicit state of a matcher includes the input character sequence as
+ * well as the <i>append position</i>, which is initially zero and is updated
+ * by the {@link #appendReplacement appendReplacement} method.
+ *
+ * <p> A matcher may be reset explicitly by invoking its {@link #reset()}
+ * method or, if a new input sequence is desired, its {@link
+ * #reset(java.lang.CharSequence) reset(CharSequence)} method.  Resetting a
+ * matcher discards its explicit state information and sets the append position
+ * to zero.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads. </p>
+ *
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ */
+
+public final class Matcher implements MatchResult {
+
+    /**
+     * The Pattern object that created this Matcher.
+     */
+    private Pattern parentPattern;
+
+    /**
+     * Holds the offsets for the most recent match.
+     */
+    int[] groups;
+
+    /**
+     * The range within the sequence that is to be matched (between  0
+     * and text.length()).
+     */
+    int from, to;
+
+    /**
+     * Holds the input text.
+     */
+    String text;
+
+    /**
+     * Reflects whether a match has been found during the most recent find
+     * operation.
+     */
+    private boolean matchFound;
+
+    private MatcherNative nativeMatcher;
+
+    /**
+     * The index of the last position appended in a substitution.
+     */
+    int appendPos = 0;
+
+    /**
+     * Holds the original CharSequence for use in {@link #reset}. {@link #text} is used during
+     * matching. Note that CharSequence is mutable while String is not, so reset can cause the input
+     * to match to change.
+     */
+    private CharSequence originalInput;
+
+    /**
+     * If transparentBounds is true then the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs that try to see beyond them.
+     */
+    boolean transparentBounds = false;
+
+    /**
+     * If anchoringBounds is true then the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     */
+    boolean anchoringBounds = true;
+
+    /**
+     * Number of times this matcher's state has been modified
+     */
+    int modCount;
+
+    // BEGIN Android-removed: Remove unused default constructor.
+    /*
+     * No default constructor.
+     *
+    Matcher() {
+    }
+    */
+    // END Android-removed: Remove unused default constructor.
+
+    /**
+     * All matchers have the state used by Pattern during a match.
+     */
+    Matcher(Pattern parent, CharSequence text) {
+        // Android-changed: Use ICU4C as the regex backend.
+        /*
+        this.parentPattern = parent;
+        this.text = text;
+
+        // Allocate state storage
+        int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
+        groups = new int[parentGroupCount * 2];
+        locals = new int[parent.localCount];
+        localsPos = new IntHashSet[parent.localTCNCount];
+
+        // Put fields into initial states
+        reset();
+        */
+        usePattern(parent);
+        reset(text);
+    }
+
+    /**
+     * Returns the pattern that is interpreted by this matcher.
+     *
+     * @return  The pattern for which this matcher was created
+     */
+    public Pattern pattern() {
+        return parentPattern;
+    }
+
+    /**
+     * Returns the match state of this matcher as a {@link MatchResult}.
+     * The result is unaffected by subsequent operations performed upon this
+     * matcher.
+     *
+     * @return  a {@code MatchResult} with the state of this matcher
+     * @throws IllegalStateException if no match is found.
+     * @since 1.5
+     */
+    public MatchResult toMatchResult() {
+        // Android-added: Throw IllegalStateException if not matched.
+        ensureMatch();
+        return toMatchResult(text.toString());
+    }
+
+    private MatchResult toMatchResult(String text) {
+        // Android-changed: Replace first and end field usages with our implementation.
+        return new ImmutableMatchResult(matchFound ? start() : -1, // this.first,
+                                        matchFound ? end() : -1, // this.last,
+                                         groupCount(),
+                                         this.groups.clone(),
+                                         text);
+    }
+
+    private static class ImmutableMatchResult implements MatchResult {
+        private final int first;
+        private final int last;
+        private final int[] groups;
+        private final int groupCount;
+        private final String text;
+
+        ImmutableMatchResult(int first, int last, int groupCount,
+                int groups[], String text)
+        {
+            this.first = first;
+            this.last = last;
+            this.groupCount = groupCount;
+            this.groups = groups;
+            this.text = text;
+        }
+
+        @Override
+        public int start() {
+            checkMatch();
+            return first;
+        }
+
+        @Override
+        public int start(int group) {
+            checkMatch();
+            if (group < 0 || group > groupCount)
+                throw new IndexOutOfBoundsException("No group " + group);
+            return groups[group * 2];
+        }
+
+        @Override
+        public int end() {
+            checkMatch();
+            return last;
+        }
+
+        @Override
+        public int end(int group) {
+            checkMatch();
+            if (group < 0 || group > groupCount)
+                throw new IndexOutOfBoundsException("No group " + group);
+            return groups[group * 2 + 1];
+        }
+
+        @Override
+        public int groupCount() {
+            return groupCount;
+        }
+
+        @Override
+        public String group() {
+            checkMatch();
+            return group(0);
+        }
+
+        @Override
+        public String group(int group) {
+            checkMatch();
+            if (group < 0 || group > groupCount)
+                throw new IndexOutOfBoundsException("No group " + group);
+            if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+                return null;
+            return text.subSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+        }
+
+        private void checkMatch() {
+            if (first < 0)
+                throw new IllegalStateException("No match found");
+
+        }
+    }
+
+    /**
+     * Changes the {@code Pattern} that this {@code Matcher} uses to
+     * find matches with.
+     *
+     * <p> This method causes this matcher to lose information
+     * about the groups of the last match that occurred. The
+     * matcher's position in the input is maintained and its
+     * last append position is unaffected.</p>
+     *
+     * @param  newPattern
+     *         The new pattern used by this matcher
+     * @return  This matcher
+     * @throws  IllegalArgumentException
+     *          If newPattern is {@code null}
+     * @since 1.5
+     */
+    public Matcher usePattern(Pattern newPattern) {
+        if (newPattern == null)
+            throw new IllegalArgumentException("Pattern cannot be null");
+
+        synchronized (this) {
+            // may throw
+            nativeMatcher = MatcherNative.create(newPattern.nativePattern);
+        }
+        parentPattern = newPattern;
+
+        if (text != null) {
+            resetForInput();
+        }
+
+        groups = new int[(groupCount() + 1) * 2];
+        matchFound = false;
+        modCount++;
+        return this;
+    }
+
+    /**
+     * Resets this matcher.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero. The matcher's region is set to the
+     * default region, which is its entire character sequence. The anchoring
+     * and transparency of this matcher's region boundaries are unaffected.
+     *
+     * @return  This matcher
+     */
+    public Matcher reset() {
+        Matcher matcher = reset(originalInput, 0, originalInput.length());
+        modCount++;
+        return matcher;
+    }
+
+    /**
+     * Resets this matcher with a new input sequence.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero.  The matcher's region is set to
+     * the default region, which is its entire character sequence.  The
+     * anchoring and transparency of this matcher's region boundaries are
+     * unaffected.
+     *
+     * @param  input
+     *         The new input character sequence
+     *
+     * @return  This matcher
+     */
+    public Matcher reset(CharSequence input) {
+        return reset(input, 0, input.length());
+    }
+
+    /**
+     * Returns the start index of the previous match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start() {
+        return start(0);
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i>{@code start(0)} is equivalent to
+     * <i>m.</i>{@code start()}.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or {@code -1} if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2];
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the
+     * previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or {@code -1} if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int start(String name) {
+        return groups[getMatchedGroupIndex(name) * 2];
+    }
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end() {
+        return end(0);
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i>{@code end(0)} is equivalent to
+     * <i>m.</i>{@code end()}.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or {@code -1} if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2 + 1];
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given <a href="Pattern.html#groupname">named-capturing
+     * group</a> during the previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or {@code -1} if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int end(String name) {
+        return groups[getMatchedGroupIndex(name) * 2 + 1];
+    }
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i>{@code group()} and
+     * <i>s.</i>{@code substring(}<i>m.</i>{@code start(),}&nbsp;<i>m.</i>
+     * {@code end())} are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example {@code a*}, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group() {
+        return group(0);
+    }
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i>{@code group(}<i>g</i>{@code )} and
+     * <i>s.</i>{@code substring(}<i>m.</i>{@code start(}<i>g</i>{@code
+     * ),}&nbsp;<i>m.</i>{@code end(}<i>g</i>{@code ))}
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression {@code m.group(0)} is equivalent to {@code m.group()}.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then {@code null} is returned. Note
+     * that some groups, for example {@code (a*)}, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or {@code null} if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the input subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the
+     * previous match operation.
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then {@code null} is returned. Note
+     * that some groups, for example {@code (a*)}, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the named group
+     *          during the previous match, or {@code null} if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.7
+     */
+    public String group(String name) {
+        int group = getMatchedGroupIndex(name);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the number of capturing groups in this matcher's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount() {
+        synchronized (this) {
+            return nativeMatcher.groupCount();
+        }
+    }
+
+    /**
+     * Attempts to match the entire region against the pattern.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * {@code start}, {@code end}, and {@code group} methods.  </p>
+     *
+     * @return  {@code true} if, and only if, the entire region sequence
+     *          matches this matcher's pattern
+     */
+    public boolean matches() {
+        synchronized (this) {
+            matchFound = nativeMatcher.matches(groups);
+        }
+        modCount++;
+        return matchFound;
+    }
+
+    /**
+     * Attempts to find the next subsequence of the input sequence that matches
+     * the pattern.
+     *
+     * <p> This method starts at the beginning of this matcher's region, or, if
+     * a previous invocation of the method was successful and the matcher has
+     * not since been reset, at the first character not matched by the previous
+     * match.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * {@code start}, {@code end}, and {@code group} methods.  </p>
+     *
+     * @return  {@code true} if, and only if, a subsequence of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean find() {
+        synchronized (this) {
+            matchFound = nativeMatcher.findNext(groups);
+        }
+        modCount++;
+        return matchFound;
+    }
+
+    /**
+     * Resets this matcher and then attempts to find the next subsequence of
+     * the input sequence that matches the pattern, starting at the specified
+     * index.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * {@code start}, {@code end}, and {@code group} methods, and subsequent
+     * invocations of the {@link #find()} method will start at the first
+     * character not matched by this match.  </p>
+     *
+     * @param start the index to start searching for a match
+     * @throws  IndexOutOfBoundsException
+     *          If start is less than zero or if start is greater than the
+     *          length of the input sequence.
+     *
+     * @return  {@code true} if, and only if, a subsequence of the input
+     *          sequence starting at the given index matches this matcher's
+     *          pattern
+     */
+    public boolean find(int start) {
+        int limit = getTextLength();
+        if ((start < 0) || (start > limit))
+            throw new IndexOutOfBoundsException("Illegal start index");
+        reset();
+        synchronized (this) {
+            matchFound = nativeMatcher.find(start, groups);
+        }
+        modCount++;
+        return matchFound;
+    }
+
+    /**
+     * Attempts to match the input sequence, starting at the beginning of the
+     * region, against the pattern.
+     *
+     * <p> Like the {@link #matches matches} method, this method always starts
+     * at the beginning of the region; unlike that method, it does not
+     * require that the entire region be matched.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * {@code start}, {@code end}, and {@code group} methods.  </p>
+     *
+     * @return  {@code true} if, and only if, a prefix of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean lookingAt() {
+        synchronized (this) {
+            matchFound = nativeMatcher.lookingAt(groups);
+        }
+        modCount++;
+        return matchFound;
+    }
+
+    /**
+     * Returns a literal replacement {@code String} for the specified
+     * {@code String}.
+     *
+     * This method produces a {@code String} that will work
+     * as a literal replacement {@code s} in the
+     * {@code appendReplacement} method of the {@link Matcher} class.
+     * The {@code String} produced will match the sequence of characters
+     * in {@code s} treated as a literal sequence. Slashes ('\') and
+     * dollar signs ('$') will be given no special meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quoteReplacement(String s) {
+        if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
+            return s;
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' || c == '$') {
+                sb.append('\\');
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Implements a non-terminal append-and-replace step.
+     *
+     * <p> This method performs the following actions: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> It reads characters from the input sequence, starting at the
+     *   append position, and appends them to the given string buffer.  It
+     *   stops after reading the last character preceding the previous match,
+     *   that is, the character at index {@link
+     *   #start()}&nbsp;{@code -}&nbsp;{@code 1}.  </p></li>
+     *
+     *   <li><p> It appends the given replacement string to the string buffer.
+     *   </p></li>
+     *
+     *   <li><p> It sets the append position of this matcher to the index of
+     *   the last character matched, plus one, that is, to {@link #end()}.
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> The replacement string may contain references to subsequences
+     * captured during the previous match: Each occurrence of
+     * <code>${</code><i>name</i><code>}</code> or {@code $}<i>g</i>
+     * will be replaced by the result of evaluating the corresponding
+     * {@link #group(String) group(name)} or {@link #group(int) group(g)}
+     * respectively. For {@code $}<i>g</i>,
+     * the first number after the {@code $} is always treated as part of
+     * the group reference. Subsequent numbers are incorporated into g if
+     * they would form a legal group reference. Only the numerals '0'
+     * through '9' are considered as potential components of the group
+     * reference. If the second group matched the string {@code "foo"}, for
+     * example, then passing the replacement string {@code "$2bar"} would
+     * cause {@code "foobar"} to be appended to the string buffer. A dollar
+     * sign ({@code $}) may be included as a literal in the replacement
+     * string by preceding it with a backslash ({@code \$}).
+     *
+     * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> This method is intended to be used in a loop together with the
+     * {@link #appendTail(StringBuffer) appendTail} and {@link #find() find}
+     * methods.  The following code, for example, writes {@code one dog two dogs
+     * in the yard} to the standard-output stream: </p>
+     *
+     * <blockquote><pre>
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuffer sb = new StringBuffer();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());</pre></blockquote>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  This matcher
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If the replacement string refers to a named-capturing
+     *          group that does not exist in the pattern
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the replacement string refers to a capturing group
+     *          that does not exist in the pattern
+     */
+    public Matcher appendReplacement(StringBuffer sb, String replacement) {
+        // TODO: Throw IllegalStateException after an SDK level check.
+        // Android-removed: Don't throw IllegalStateException due to app compat
+        // If no match, return error
+        // if (first < 0)
+        //     throw new IllegalStateException("No match available");
+        StringBuilder result = new StringBuilder();
+        // Android-changed: Use Android's appendEvaluated due to app compat.
+        // appendExpandedReplacement(replacement, result);
+        appendReplacementInternal(result, replacement);
+        // Append the intervening text
+        // Android-changed: Android has no lastAppendPosition.
+        // sb.append(text, lastAppendPosition, first);
+        sb.append(text, appendPos, start());
+        // Append the match substitution
+        sb.append(result);
+        // Android-changed: Android has no lastAppendPosition.
+        // lastAppendPosition = last;
+        appendPos = end();
+        modCount++;
+        return this;
+    }
+
+    // BEGIN Android-added: Backward-compatible codes for appendReplacement().
+    /**
+     * Since Android 14, {@link Matcher} becomes stricter for the replacement syntax and
+     * group references used by its methods, e.g. {@link #appendReplacement(StringBuffer, String)}.
+     *
+     * This flag is enabled for apps targeting Android 14+.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.UPSIDE_DOWN_CAKE)
+    public static final long DISALLOW_INVALID_GROUP_REFERENCE = 247079863L;
+
+    private void appendReplacementInternal(StringBuilder sb, String replacement) {
+        if (VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE
+                && Compatibility.isChangeEnabled(DISALLOW_INVALID_GROUP_REFERENCE)) {
+            appendExpandedReplacement(replacement, sb);
+        } else {
+            appendEvaluated(sb, replacement);
+        }
+    }
+
+    /**
+     * Internal helper method to append a given string to a given string buffer.
+     * If the string contains any references to groups, these are replaced by
+     * the corresponding group's contents.
+     *
+     * @param buffer the string builder.
+     * @param s the string to append.
+     *
+     * @hide
+     */
+    public void appendEvaluated(StringBuilder buffer, String s) {
+        boolean escape = false;
+        boolean dollar = false;
+        boolean escapeNamedGroup = false;
+        int escapeNamedGroupStart = -1;
+
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' && !escape) {
+                escape = true;
+            } else if (c == '$' && !escape) {
+                dollar = true;
+            } else if (c >= '0' && c <= '9' && dollar && !escapeNamedGroup) {
+                String groupValue = group(c - '0');
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+            } else if (c == '{' && dollar) {
+                escapeNamedGroup = true;
+                escapeNamedGroupStart = i;
+            } else if (c == '}' && dollar && escapeNamedGroup) {
+                String groupValue = group(s.substring(escapeNamedGroupStart + 1, i));
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+                escapeNamedGroup = false;
+            } else if (c != '}' && dollar && escapeNamedGroup) {
+                continue;
+            } else {
+                buffer.append(c);
+                dollar = false;
+                escape = false;
+                escapeNamedGroup = false;
+            }
+        }
+
+        if (escape) {
+            throw new IllegalArgumentException("character to be escaped is missing");
+        }
+
+        if (dollar) {
+            throw new IllegalArgumentException("Illegal group reference: group index is missing");
+        }
+
+        if (escapeNamedGroup) {
+            throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
+        }
+    }
+    // END Android-added: Backward-compatible codes for appendReplacement().
+
+    /**
+     * Implements a non-terminal append-and-replace step.
+     *
+     * <p> This method performs the following actions: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> It reads characters from the input sequence, starting at the
+     *   append position, and appends them to the given string builder.  It
+     *   stops after reading the last character preceding the previous match,
+     *   that is, the character at index {@link
+     *   #start()}&nbsp;{@code -}&nbsp;{@code 1}.  </p></li>
+     *
+     *   <li><p> It appends the given replacement string to the string builder.
+     *   </p></li>
+     *
+     *   <li><p> It sets the append position of this matcher to the index of
+     *   the last character matched, plus one, that is, to {@link #end()}.
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> The replacement string may contain references to subsequences
+     * captured during the previous match: Each occurrence of
+     * {@code $}<i>g</i> will be replaced by the result of
+     * evaluating {@link #group(int) group}{@code (}<i>g</i>{@code )}.
+     * The first number after the {@code $} is always treated as part of
+     * the group reference. Subsequent numbers are incorporated into g if
+     * they would form a legal group reference. Only the numerals '0'
+     * through '9' are considered as potential components of the group
+     * reference. If the second group matched the string {@code "foo"}, for
+     * example, then passing the replacement string {@code "$2bar"} would
+     * cause {@code "foobar"} to be appended to the string builder. A dollar
+     * sign ({@code $}) may be included as a literal in the replacement
+     * string by preceding it with a backslash ({@code \$}).
+     *
+     * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> This method is intended to be used in a loop together with the
+     * {@link #appendTail(StringBuilder) appendTail} and
+     * {@link #find() find} methods. The following code, for example, writes
+     * {@code one dog two dogs in the yard} to the standard-output stream: </p>
+     *
+     * <blockquote><pre>
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuilder sb = new StringBuilder();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());</pre></blockquote>
+     *
+     * @param  sb
+     *         The target string builder
+     * @param  replacement
+     *         The replacement string
+     * @return  This matcher
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     * @throws  IllegalArgumentException
+     *          If the replacement string refers to a named-capturing
+     *          group that does not exist in the pattern
+     * @throws  IndexOutOfBoundsException
+     *          If the replacement string refers to a capturing group
+     *          that does not exist in the pattern
+     * @since 9
+     */
+    public Matcher appendReplacement(StringBuilder sb, String replacement) {
+        // If no match, return error
+        // Android-changed: Android has no first field.
+        // if (first < 0)
+        //     throw new IllegalStateException("No match available");
+        ensureMatch();
+        StringBuilder result = new StringBuilder();
+        // Android-changed: Use Android's appendEvaluated due to app compat.
+        // appendExpandedReplacement(replacement, result);
+        appendReplacementInternal(result, replacement);
+        // Append the intervening text
+        // Android-changed: Android has no lastAppendPosition.
+        // sb.append(text, lastAppendPosition, first);
+        sb.append(text, appendPos, start());
+        // Append the match substitution
+        sb.append(result);
+        // Android-changed: Android has no lastAppendPosition.
+        // lastAppendPosition = last;
+        appendPos = end();
+        modCount++;
+        return this;
+    }
+
+    // Android-changed: Make public for testing.
+    /**
+     * Processes replacement string to replace group references with
+     * groups.
+     *
+     * @hide
+     */
+    public StringBuilder appendExpandedReplacement(
+            String replacement, StringBuilder result) {
+        int cursor = 0;
+        while (cursor < replacement.length()) {
+            char nextChar = replacement.charAt(cursor);
+            if (nextChar == '\\') {
+                cursor++;
+                if (cursor == replacement.length())
+                    throw new IllegalArgumentException(
+                            "character to be escaped is missing");
+                nextChar = replacement.charAt(cursor);
+                result.append(nextChar);
+                cursor++;
+            } else if (nextChar == '$') {
+                // Skip past $
+                cursor++;
+                // Throw IAE if this "$" is the last character in replacement
+                if (cursor == replacement.length())
+                    throw new IllegalArgumentException(
+                            "Illegal group reference: group index is missing");
+                nextChar = replacement.charAt(cursor);
+                int refNum = -1;
+                if (nextChar == '{') {
+                    cursor++;
+                    StringBuilder gsb = new StringBuilder();
+                    while (cursor < replacement.length()) {
+                        nextChar = replacement.charAt(cursor);
+                        if (ASCII.isLower(nextChar) ||
+                                ASCII.isUpper(nextChar) ||
+                                ASCII.isDigit(nextChar)) {
+                            gsb.append(nextChar);
+                            cursor++;
+                        } else {
+                            break;
+                        }
+                    }
+                    if (gsb.length() == 0)
+                        throw new IllegalArgumentException(
+                                "named capturing group has 0 length name");
+                    if (nextChar != '}')
+                        throw new IllegalArgumentException(
+                                "named capturing group is missing trailing '}'");
+                    String gname = gsb.toString();
+                    if (ASCII.isDigit(gname.charAt(0)))
+                        throw new IllegalArgumentException(
+                                "capturing group name {" + gname +
+                                        "} starts with digit character");
+                    // Android-changed: Use ICU4C as the regex backend.
+                    // if (!parentPattern.namedGroups().containsKey(gname))
+                    int groupIndex = nativeMatcher.getMatchedGroupIndex(gname);
+                    if (groupIndex < 0)
+                        throw new IllegalArgumentException(
+                                "No group with name {" + gname + "}");
+                    refNum = groupIndex;
+                    cursor++;
+                } else {
+                    // The first number is always a group
+                    refNum = nextChar - '0';
+                    if ((refNum < 0) || (refNum > 9))
+                        throw new IllegalArgumentException(
+                                "Illegal group reference");
+                    cursor++;
+                    // Capture the largest legal group string
+                    boolean done = false;
+                    while (!done) {
+                        if (cursor >= replacement.length()) {
+                            break;
+                        }
+                        int nextDigit = replacement.charAt(cursor) - '0';
+                        if ((nextDigit < 0) || (nextDigit > 9)) { // not a number
+                            break;
+                        }
+                        int newRefNum = (refNum * 10) + nextDigit;
+                        if (groupCount() < newRefNum) {
+                            done = true;
+                        } else {
+                            refNum = newRefNum;
+                            cursor++;
+                        }
+                    }
+                }
+                // Append group
+                if (start(refNum) != -1 && end(refNum) != -1)
+                    result.append(text, start(refNum), end(refNum));
+            } else {
+                result.append(nextChar);
+                cursor++;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Implements a terminal append-and-replace step.
+     *
+     * <p> This method reads characters from the input sequence, starting at
+     * the append position, and appends them to the given string buffer.  It is
+     * intended to be invoked after one or more invocations of the {@link
+     * #appendReplacement(StringBuffer, String) appendReplacement} method in
+     * order to copy the remainder of the input sequence.  </p>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @return  The target string buffer
+     */
+    public StringBuffer appendTail(StringBuffer sb) {
+        // Android-changed: Android has no lastAppendPosition.
+        // sb.append(text, lastAppendPosition, getTextLength());
+        if (appendPos < to) {
+            sb.append(text.substring(appendPos, to));
+        }
+        return sb;
+    }
+
+    /**
+     * Implements a terminal append-and-replace step.
+     *
+     * <p> This method reads characters from the input sequence, starting at
+     * the append position, and appends them to the given string builder.  It is
+     * intended to be invoked after one or more invocations of the {@link
+     * #appendReplacement(StringBuilder, String)
+     * appendReplacement} method in order to copy the remainder of the input
+     * sequence.  </p>
+     *
+     * @param  sb
+     *         The target string builder
+     *
+     * @return  The target string builder
+     *
+     * @since 9
+     */
+    public StringBuilder appendTail(StringBuilder sb) {
+        // Android-changed: Android has no lastAppendPosition.
+        // sb.append(text, lastAppendPosition, getTextLength());
+        if (appendPos < to) {
+            sb.append(text.substring(appendPos, to));
+        }
+        return sb;
+    }
+
+    /**
+     * Replaces every subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for matches of the pattern.  Characters that are not
+     * part of any match are appended directly to the result string; each match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression {@code a*b}, the input
+     * {@code "aabfooaabfooabfoob"}, and the replacement string
+     * {@code "-"}, an invocation of this method on a matcher for that
+     * expression would yield the string {@code "-foo-foo-foo-"}.
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  The string constructed by replacing each matching subsequence
+     *          by the replacement string, substituting captured subsequences
+     *          as needed
+     */
+    public String replaceAll(String replacement) {
+        reset();
+        boolean result = find();
+        if (result) {
+            StringBuilder sb = new StringBuilder();
+            do {
+                appendReplacement(sb, replacement);
+                result = find();
+            } while (result);
+            appendTail(sb);
+            return sb.toString();
+        }
+        return text.toString();
+    }
+
+    /**
+     * Replaces every subsequence of the input sequence that matches the
+     * pattern with the result of applying the given replacer function to the
+     * match result of this matcher corresponding to that subsequence.
+     * Exceptions thrown by the function are relayed to the caller.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for matches of the pattern.  Characters that are not
+     * part of any match are appended directly to the result string; each match
+     * is replaced in the result by the applying the replacer function that
+     * returns a replacement string.  Each replacement string may contain
+     * references to captured subsequences as in the {@link #appendReplacement
+     * appendReplacement} method.
+     *
+     * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * a replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression {@code dog}, the input
+     * {@code "zzzdogzzzdogzzz"}, and the function
+     * {@code mr -> mr.group().toUpperCase()}, an invocation of this method on
+     * a matcher for that expression would yield the string
+     * {@code "zzzDOGzzzDOGzzz"}.
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * <p> The replacer function should not modify this matcher's state during
+     * replacement.  This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if such modification is
+     * detected.
+     *
+     * <p> The state of each match result passed to the replacer function is
+     * guaranteed to be constant only for the duration of the replacer function
+     * call and only if the replacer function does not modify this matcher's
+     * state.
+     *
+     * @implNote
+     * This implementation applies the replacer function to this matcher, which
+     * is an instance of {@code MatchResult}.
+     *
+     * @param  replacer
+     *         The function to be applied to the match result of this matcher
+     *         that returns a replacement string.
+     * @return  The string constructed by replacing each matching subsequence
+     *          with the result of applying the replacer function to that
+     *          matched subsequence, substituting captured subsequences as
+     *          needed.
+     * @throws NullPointerException if the replacer function is null
+     * @throws ConcurrentModificationException if it is detected, on a
+     *         best-effort basis, that the replacer function modified this
+     *         matcher's state
+     * @since 9
+     */
+    public String replaceAll(Function<MatchResult, String> replacer) {
+        Objects.requireNonNull(replacer);
+        reset();
+        boolean result = find();
+        if (result) {
+            StringBuilder sb = new StringBuilder();
+            do {
+                int ec = modCount;
+                String replacement =  replacer.apply(this);
+                if (ec != modCount)
+                    throw new ConcurrentModificationException();
+                appendReplacement(sb, replacement);
+                result = find();
+            } while (result);
+            appendTail(sb);
+            return sb.toString();
+        }
+        return text.toString();
+    }
+
+    /**
+     * Returns a stream of match results for each subsequence of the input
+     * sequence that matches the pattern.  The match results occur in the
+     * same order as the matching subsequences in the input sequence.
+     *
+     * <p> Each match result is produced as if by {@link #toMatchResult()}.
+     *
+     * <p> This method does not reset this matcher.  Matching starts on
+     * initiation of the terminal stream operation either at the beginning of
+     * this matcher's region, or, if the matcher has not since been reset, at
+     * the first character not matched by a previous match.
+     *
+     * <p> If the matcher is to be used for further matching operations after
+     * the terminal stream operation completes then it should be first reset.
+     *
+     * <p> This matcher's state should not be modified during execution of the
+     * returned stream's pipeline.  The returned stream's source
+     * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort
+     * basis, throw a {@link java.util.ConcurrentModificationException} if such
+     * modification is detected.
+     *
+     * @return a sequential stream of match results.
+     * @since 9
+     */
+    public Stream<MatchResult> results() {
+        class MatchResultIterator implements Iterator<MatchResult> {
+            // -ve for call to find, 0 for not found, 1 for found
+            int state = -1;
+            // State for concurrent modification checking
+            // -1 for uninitialized
+            int expectedCount = -1;
+            // The input sequence as a string, set once only after first find
+            // Avoids repeated conversion from CharSequence for each match
+            String textAsString;
+
+            @Override
+            public MatchResult next() {
+                if (expectedCount >= 0 && expectedCount != modCount)
+                    throw new ConcurrentModificationException();
+
+                if (!hasNext())
+                    throw new NoSuchElementException();
+
+                state = -1;
+                return toMatchResult(textAsString);
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (state >= 0)
+                    return state == 1;
+
+                // Defer throwing ConcurrentModificationException to when next
+                // or forEachRemaining is called.  The is consistent with other
+                // fail-fast implementations.
+                if (expectedCount >= 0 && expectedCount != modCount)
+                    return true;
+
+                boolean found = find();
+                // Capture the input sequence as a string on first find
+                if (found && state < 0)
+                    textAsString = text.toString();
+                state = found ? 1 : 0;
+                expectedCount = modCount;
+                return found;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super MatchResult> action) {
+                if (expectedCount >= 0 && expectedCount != modCount)
+                    throw new ConcurrentModificationException();
+
+                int s = state;
+                if (s == 0)
+                    return;
+
+                // Set state to report no more elements on further operations
+                state = 0;
+                expectedCount = -1;
+
+                // Perform a first find if required
+                if (s < 0 && !find())
+                    return;
+
+                // Capture the input sequence as a string on first find
+                textAsString = text.toString();
+
+                do {
+                    int ec = modCount;
+                    action.accept(toMatchResult(textAsString));
+                    if (ec != modCount)
+                        throw new ConcurrentModificationException();
+                } while (find());
+            }
+        }
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                new MatchResultIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Replaces the first subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for a match of the pattern.  Characters that are not
+     * part of the match are appended directly to the result string; the match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p>Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression {@code dog}, the input
+     * {@code "zzzdogzzzdogzzz"}, and the replacement string
+     * {@code "cat"}, an invocation of this method on a matcher for that
+     * expression would yield the string {@code "zzzcatzzzdogzzz"}.  </p>
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     * @return  The string constructed by replacing the first matching
+     *          subsequence by the replacement string, substituting captured
+     *          subsequences as needed
+     */
+    public String replaceFirst(String replacement) {
+        if (replacement == null)
+            throw new NullPointerException("replacement");
+        reset();
+        if (!find())
+            return text.toString();
+        StringBuilder sb = new StringBuilder();
+        appendReplacement(sb, replacement);
+        appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * Replaces the first subsequence of the input sequence that matches the
+     * pattern with the result of applying the given replacer function to the
+     * match result of this matcher corresponding to that subsequence.
+     * Exceptions thrown by the replace function are relayed to the caller.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for a match of the pattern.  Characters that are not
+     * part of the match are appended directly to the result string; the match
+     * is replaced in the result by the applying the replacer function that
+     * returns a replacement string.  The replacement string may contain
+     * references to captured subsequences as in the {@link #appendReplacement
+     * appendReplacement} method.
+     *
+     * <p>Note that backslashes ({@code \}) and dollar signs ({@code $}) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression {@code dog}, the input
+     * {@code "zzzdogzzzdogzzz"}, and the function
+     * {@code mr -> mr.group().toUpperCase()}, an invocation of this method on
+     * a matcher for that expression would yield the string
+     * {@code "zzzDOGzzzdogzzz"}.
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.
+     *
+     * <p> The replacer function should not modify this matcher's state during
+     * replacement.  This method will, on a best-effort basis, throw a
+     * {@link java.util.ConcurrentModificationException} if such modification is
+     * detected.
+     *
+     * <p> The state of the match result passed to the replacer function is
+     * guaranteed to be constant only for the duration of the replacer function
+     * call and only if the replacer function does not modify this matcher's
+     * state.
+     *
+     * @implNote
+     * This implementation applies the replacer function to this matcher, which
+     * is an instance of {@code MatchResult}.
+     *
+     * @param  replacer
+     *         The function to be applied to the match result of this matcher
+     *         that returns a replacement string.
+     * @return  The string constructed by replacing the first matching
+     *          subsequence with the result of applying the replacer function to
+     *          the matched subsequence, substituting captured subsequences as
+     *          needed.
+     * @throws NullPointerException if the replacer function is null
+     * @throws ConcurrentModificationException if it is detected, on a
+     *         best-effort basis, that the replacer function modified this
+     *         matcher's state
+     * @since 9
+     */
+    public String replaceFirst(Function<MatchResult, String> replacer) {
+        Objects.requireNonNull(replacer);
+        reset();
+        if (!find())
+            return text.toString();
+        StringBuilder sb = new StringBuilder();
+        int ec = modCount;
+        String replacement = replacer.apply(this);
+        if (ec != modCount)
+            throw new ConcurrentModificationException();
+        appendReplacement(sb, replacement);
+        appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * Sets the limits of this matcher's region. The region is the part of the
+     * input sequence that will be searched to find a match. Invoking this
+     * method resets the matcher, and then sets the region to start at the
+     * index specified by the {@code start} parameter and end at the
+     * index specified by the {@code end} parameter.
+     *
+     * <p>Depending on the transparency and anchoring being used (see
+     * {@link #useTransparentBounds(boolean) useTransparentBounds} and
+     * {@link #useAnchoringBounds(boolean) useAnchoringBounds}), certain
+     * constructs such as anchors may behave differently at or around the
+     * boundaries of the region.
+     *
+     * @param  start
+     *         The index to start searching at (inclusive)
+     * @param  end
+     *         The index to end searching at (exclusive)
+     * @throws  IndexOutOfBoundsException
+     *          If start or end is less than zero, if
+     *          start is greater than the length of the input sequence, if
+     *          end is greater than the length of the input sequence, or if
+     *          start is greater than end.
+     * @return  this matcher
+     * @since 1.5
+     */
+    public Matcher region(int start, int end) {
+        return reset(originalInput, start, end);
+    }
+
+    /**
+     * Reports the start index of this matcher's region. The
+     * searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart() regionStart} (inclusive) and
+     * {@link #regionEnd() regionEnd} (exclusive).
+     *
+     * @return  The starting point of this matcher's region
+     * @since 1.5
+     */
+    public int regionStart() {
+        return from;
+    }
+
+    /**
+     * Reports the end index (exclusive) of this matcher's region.
+     * The searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart() regionStart} (inclusive) and
+     * {@link #regionEnd() regionEnd} (exclusive).
+     *
+     * @return  the ending point of this matcher's region
+     * @since 1.5
+     */
+    public int regionEnd() {
+        return to;
+    }
+
+    /**
+     * Queries the transparency of region bounds for this matcher.
+     *
+     * <p> This method returns {@code true} if this matcher uses
+     * <i>transparent</i> bounds, {@code false} if it uses <i>opaque</i>
+     * bounds.
+     *
+     * <p> See {@link #useTransparentBounds(boolean) useTransparentBounds} for a
+     * description of transparent and opaque bounds.
+     *
+     * <p> By default, a matcher uses opaque region boundaries.
+     *
+     * @return {@code true} iff this matcher is using transparent bounds,
+     *         {@code false} otherwise.
+     * @see java.util.regex.Matcher#useTransparentBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasTransparentBounds() {
+        return transparentBounds;
+    }
+
+    /**
+     * Sets the transparency of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of {@code true} will set this
+     * matcher to use <i>transparent</i> bounds. If the boolean
+     * argument is {@code false}, then <i>opaque</i> bounds will be used.
+     *
+     * <p> Using transparent bounds, the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs. Those constructs can see beyond the
+     * boundaries of the region to see if a match is appropriate.
+     *
+     * <p> Using opaque bounds, the boundaries of this matcher's
+     * region are opaque to lookahead, lookbehind, and boundary matching
+     * constructs that may try to see beyond them. Those constructs cannot
+     * look past the boundaries so they will fail to match anything outside
+     * of the region.
+     *
+     * <p> By default, a matcher uses opaque bounds.
+     *
+     * @param  b a boolean indicating whether to use opaque or transparent
+     *         regions
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasTransparentBounds
+     * @since 1.5
+     */
+    public Matcher useTransparentBounds(boolean b) {
+        synchronized (this) {
+            transparentBounds = b;
+            nativeMatcher.useTransparentBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * Queries the anchoring of region bounds for this matcher.
+     *
+     * <p> This method returns {@code true} if this matcher uses
+     * <i>anchoring</i> bounds, {@code false} otherwise.
+     *
+     * <p> See {@link #useAnchoringBounds(boolean) useAnchoringBounds} for a
+     * description of anchoring bounds.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @return {@code true} iff this matcher is using anchoring bounds,
+     *         {@code false} otherwise.
+     * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasAnchoringBounds() {
+        return anchoringBounds;
+    }
+
+    /**
+     * Sets the anchoring of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of {@code true} will set this
+     * matcher to use <i>anchoring</i> bounds. If the boolean
+     * argument is {@code false}, then <i>non-anchoring</i> bounds will be
+     * used.
+     *
+     * <p> Using anchoring bounds, the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     *
+     * <p> Without anchoring bounds, the boundaries of this
+     * matcher's region will not match anchors such as ^ and $.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @param  b a boolean indicating whether or not to use anchoring bounds.
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasAnchoringBounds
+     * @since 1.5
+     */
+    public Matcher useAnchoringBounds(boolean b) {
+        synchronized (this) {
+            anchoringBounds = b;
+            nativeMatcher.useAnchoringBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Returns the string representation of this matcher. The
+     * string representation of a {@code Matcher} contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this matcher
+     * @since 1.5
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.regex.Matcher")
+                .append("[pattern=").append(pattern())
+                .append(" region=")
+                .append(regionStart()).append(',').append(regionEnd())
+                .append(" lastmatch=");
+        // Android-changed: Android has no first field.
+        // if ((first >= 0) && (group() != null)) {
+        if (matchFound && (group() != null)) {
+            sb.append(group());
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+    /**
+     * <p>Returns true if the end of input was hit by the search engine in
+     * the last match operation performed by this matcher.
+     *
+     * <p>When this method returns true, then it is possible that more input
+     * would have changed the result of the last search.
+     *
+     * @return  true iff the end of input was hit in the last match; false
+     *          otherwise
+     * @since 1.5
+     */
+    public boolean hitEnd() {
+        synchronized (this) {
+            return nativeMatcher.hitEnd();
+        }
+    }
+
+    /**
+     * <p>Returns true if more input could change a positive match into a
+     * negative one.
+     *
+     * <p>If this method returns true, and a match was found, then more
+     * input could cause the match to be lost. If this method returns false
+     * and a match was found, then more input might change the match but the
+     * match won't be lost. If a match was not found, then requireEnd has no
+     * meaning.
+     *
+     * @return  true iff more input could change a positive match into a
+     *          negative one.
+     * @since 1.5
+     */
+    public boolean requireEnd() {
+        synchronized (this) {
+            return nativeMatcher.requireEnd();
+        }
+    }
+
+    /**
+     * Returns the end index of the text.
+     *
+     * @return the index after the last character in the text
+     */
+    int getTextLength() {
+        return text.length();
+    }
+
+    /**
+     * Generates a String from this matcher's input in the specified range.
+     *
+     * @param  beginIndex   the beginning index, inclusive
+     * @param  endIndex     the ending index, exclusive
+     * @return A String generated from this matcher's input
+     */
+    CharSequence getSubSequence(int beginIndex, int endIndex) {
+        return text.subSequence(beginIndex, endIndex);
+    }
+
+    /**
+     * Resets the Matcher. A new input sequence and a new region can be
+     * specified. Results of a previous find get lost. The next attempt to find
+     * an occurrence of the Pattern in the string will start at the beginning of
+     * the region. This is the internal version of reset() to which the several
+     * public versions delegate.
+     *
+     * @param input
+     *            the input sequence.
+     * @param start
+     *            the start of the region.
+     * @param end
+     *            the end of the region.
+     *
+     * @return the matcher itself.
+     */
+    private Matcher reset(CharSequence input, int start, int end) {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null");
+        }
+
+        if (start < 0 || end < 0 || start > input.length() || end > input.length() || start > end) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        this.originalInput = input;
+        this.text = input.toString();
+        this.from = start;
+        this.to = end;
+        resetForInput();
+
+        matchFound = false;
+        appendPos = 0;
+        modCount++;
+
+        return this;
+    }
+
+    private void resetForInput() {
+        synchronized (this) {
+            nativeMatcher.setInput(text, from, to);
+            nativeMatcher.useAnchoringBounds(anchoringBounds);
+            nativeMatcher.useTransparentBounds(transparentBounds);
+        }
+    }
+
+    /**
+     * Makes sure that a successful match has been made. Is invoked internally
+     * from various places in the class.
+     *
+     * @throws IllegalStateException
+     *             if no successful match has been made.
+     */
+    private void ensureMatch() {
+        if (!matchFound) {
+            throw new IllegalStateException("No successful match so far");
+        }
+    }
+
+    private int getMatchedGroupIndex(String name) {
+        ensureMatch();
+        int result = nativeMatcher.getMatchedGroupIndex(name);
+        if (result < 0) {
+            throw new IllegalArgumentException("No capturing group in the pattern " +
+                                               "with the name " + name);
+        }
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/android-35/java/util/regex/Pattern.java b/android-35/java/util/regex/Pattern.java
new file mode 100644
index 0000000..43fa233
--- /dev/null
+++ b/android-35/java/util/regex/Pattern.java
@@ -0,0 +1,5801 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+
+import com.android.icu.util.regex.PatternNative;
+
+import dalvik.annotation.compat.VersionCodes;
+import dalvik.system.VMRuntime;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import libcore.util.EmptyArray;
+
+// Android-changed: Document that named capturing is only available from API 26.
+// Android-changed: Android always uses unicode character classes.
+// Android-changed: Remove reference to Character.codePointOf(String) until it's implemented.
+// Android-changed: UNICODE_CHARACTER_CLASS causes IllegalArgumentException on Android.
+// Android-changed: POSIX character classes are Unicode-aware.
+// Android-changed: Throw PatternSyntaxException for non-existent back references.
+// Android-changed: Remove "Compatibility Properties of Unicode Regular Expression" table.
+// Android-changed: Remove supported \b{g} Unicode extended grapheme cluster boundary.
+// Android-changed: Prefix "Is" is supported since Android 10. http://b/110364810
+/**
+ * A compiled representation of a regular expression.
+ *
+ * <p> A regular expression, specified as a string, must first be compiled into
+ * an instance of this class.  The resulting pattern can then be used to create
+ * a {@link Matcher} object that can match arbitrary {@linkplain
+ * java.lang.CharSequence character sequences} against the regular
+ * expression.  All of the state involved in performing a match resides in the
+ * matcher, so many matchers can share the same pattern.
+ *
+ * <p> A typical invocation sequence is thus
+ *
+ * <blockquote><pre>
+ * Pattern p = Pattern.{@link #compile compile}("a*b");
+ * Matcher m = p.{@link #matcher matcher}("aaaaab");
+ * boolean b = m.{@link Matcher#matches matches}();</pre></blockquote>
+ *
+ * <p> A {@link #matches matches} method is defined by this class as a
+ * convenience for when a regular expression is used just once.  This method
+ * compiles an expression and matches an input sequence against it in a single
+ * invocation.  The statement
+ *
+ * <blockquote><pre>
+ * boolean b = Pattern.matches("a*b", "aaaaab");</pre></blockquote>
+ *
+ * is equivalent to the three statements above, though for repeated matches it
+ * is less efficient since it does not allow the compiled pattern to be reused.
+ *
+ * <p> Instances of this class are immutable and are safe for use by multiple
+ * concurrent threads.  Instances of the {@link Matcher} class are not safe for
+ * such use.
+ *
+ *
+ * <h2><a id="sum">Summary of regular-expression constructs</a></h2>
+ *
+ * <table class="borderless">
+ * <caption style="display:none">Regular expression constructs, and what they match</caption>
+ * <thead style="text-align:left">
+ * <tr>
+ * <th id="construct">Construct</th>
+ * <th id="matches">Matches</th>
+ * </tr>
+ * </thead>
+ * <tbody style="text-align:left">
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="characters">Characters</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight: normal" id="x"><i>x</i></th>
+ *     <td headers="matches characters x">The character <i>x</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="backslash">{@code \\}</th>
+ *     <td headers="matches characters backslash">The backslash character</td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="octal_n">{@code \0}<i>n</i></th>
+ *     <td headers="matches characters octal_n">The character with octal value {@code 0}<i>n</i>
+ *         (0&nbsp;{@code <=}&nbsp;<i>n</i>&nbsp;{@code <=}&nbsp;7)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="octal_nn">{@code \0}<i>nn</i></th>
+ *     <td headers="matches characters octal_nn">The character with octal value {@code 0}<i>nn</i>
+ *         (0&nbsp;{@code <=}&nbsp;<i>n</i>&nbsp;{@code <=}&nbsp;7)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="octal_nnn">{@code \0}<i>mnn</i></th>
+ *     <td headers="matches characters octal_nnn">The character with octal value {@code 0}<i>mnn</i>
+ *         (0&nbsp;{@code <=}&nbsp;<i>m</i>&nbsp;{@code <=}&nbsp;3,
+ *         0&nbsp;{@code <=}&nbsp;<i>n</i>&nbsp;{@code <=}&nbsp;7)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="hex_hh">{@code \x}<i>hh</i></th>
+ *     <td headers="matches characters hex_hh">The character with hexadecimal value {@code 0x}<i>hh</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="hex_hhhh"><code>&#92;u</code><i>hhhh</i></th>
+ *     <td headers="matches characters hex_hhhh">The character with hexadecimal&nbsp;value&nbsp;{@code 0x}<i>hhhh</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="hex_h_h"><code>&#92;x</code><i>{h...h}</i></th>
+ *     <td headers="matches characters hex_h_h">The character with hexadecimal value {@code 0x}<i>h...h</i>
+ *         ({@link java.lang.Character#MIN_CODE_POINT Character.MIN_CODE_POINT}
+ *         &nbsp;&lt;=&nbsp;{@code 0x}<i>h...h</i>&nbsp;&lt;=&nbsp;
+ *          {@link java.lang.Character#MAX_CODE_POINT Character.MAX_CODE_POINT})</td></tr>
+ * <tr><th style="vertical-align:top; font-weight: normal" id="unicode_name"><code>&#92;N{</code><i>name</i><code>}</code></th>
+ *     <td headers="matches characters unicode_name">The character with Unicode character name <i>'name'</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="tab">{@code \t}</th>
+ *     <td headers="matches characters tab">The tab character (<code>'&#92;u0009'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="newline">{@code \n}</th>
+ *     <td headers="matches characters newline">The newline (line feed) character (<code>'&#92;u000A'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="return">{@code \r}</th>
+ *     <td headers="matches characters return">The carriage-return character (<code>'&#92;u000D'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="form_feed">{@code \f}</th>
+ *     <td headers="matches characters form_feed">The form-feed character (<code>'&#92;u000C'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="bell">{@code \a}</th>
+ *     <td headers="matches characters bell">The alert (bell) character (<code>'&#92;u0007'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="escape">{@code \e}</th>
+ *     <td headers="matches characters escape">The escape character (<code>'&#92;u001B'</code>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="ctrl_x">{@code \c}<i>x</i></th>
+ *     <td headers="matches characters ctrl_x">The control character corresponding to <i>x</i></td></tr>
+ *
+ *  <tr><th colspan="2" style="padding-top:20px" id="classes">Character classes</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="simple">{@code [abc]}</th>
+ *     <td headers="matches classes simple">{@code a}, {@code b}, or {@code c} (simple class)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="negation">{@code [^abc]}</th>
+ *     <td headers="matches classes negation">Any character except {@code a}, {@code b}, or {@code c} (negation)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="range">{@code [a-zA-Z]}</th>
+ *     <td headers="matches classes range">{@code a} through {@code z}
+ *         or {@code A} through {@code Z}, inclusive (range)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="union">{@code [a-d[m-p]]}</th>
+ *     <td headers="matches classes union">{@code a} through {@code d},
+ *      or {@code m} through {@code p}: {@code [a-dm-p]} (union)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="intersection">{@code [a-z&&[def]]}</th>
+ *     <td headers="matches classes intersection">{@code d}, {@code e}, or {@code f} (intersection)</tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="subtraction1">{@code [a-z&&[^bc]]}</th>
+ *     <td headers="matches classes subtraction1">{@code a} through {@code z},
+ *         except for {@code b} and {@code c}: {@code [ad-z]} (subtraction)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="subtraction2">{@code [a-z&&[^m-p]]}</th>
+ *     <td headers="matches classes subtraction2">{@code a} through {@code z},
+ *          and not {@code m} through {@code p}: {@code [a-lq-z]}(subtraction)</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="predef">Predefined character classes</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="any">{@code .}</th>
+ *     <td headers="matches predef any">Any character (may or may not match <a href="#lt">line terminators</a>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="digit">{@code \d}</th>
+ *     <td headers="matches predef digit">A digit: {@code \p{IsDigit}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_digit">{@code \D}</th>
+ *     <td headers="matches predef non_digit">A non-digit: {@code  [^\d]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="horiz_white">{@code \h}</th>
+ *     <td headers="matches predef horiz_white">A horizontal whitespace character:
+ *     <code>[ \t\xA0&#92;u1680&#92;u180e&#92;u2000-&#92;u200a&#92;u202f&#92;u205f&#92;u3000]</code></td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_horiz_white">{@code \H}</th>
+ *     <td headers="matches predef non_horiz_white">A non-horizontal whitespace character: {@code [^\h]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="white">{@code \s}</th>
+ *     <td headers="matches predef white">A whitespace character: {@code \p{IsWhite_Space}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_white">{@code \S}</th>
+ *     <td headers="matches predef non_white">A non-whitespace character: {@code [^\s]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="vert_white">{@code \v}</th>
+ *     <td headers="matches predef vert_white">A vertical whitespace character: <code>[\n\x0B\f\r\x85&#92;u2028&#92;u2029]</code>
+ *     </td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_vert_white">{@code \V}</th>
+ *     <td headers="matches predef non_vert_white">A non-vertical whitespace character: {@code [^\v]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="word">{@code \w}</th>
+ *     <td headers="matches predef word">A word character: {@code [\p{alpha}\p{gc=Mark}\p{digit}\p{gc=Connector_Punctuation}\p{Join_Control}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_word">{@code \W}</th>
+ *     <td headers="matches predef non_word">A non-word character: {@code [^\w]}</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="posix"><b>POSIX character classes (Unicode-aware)</b></th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Lower">{@code \p{Lower}}</th>
+ *     <td headers="matches posix Lower">A lower-case alphabetic character: {@code \p{IsLowercase}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Upper">{@code \p{Upper}}</th>
+ *     <td headers="matches posix Upper">An upper-case alphabetic character:{@code \p{IsUppercase}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="ASCII">{@code \p{ASCII}}</th>
+ *     <td headers="matches posix ASCII">All ASCII:{@code [\x00-\x7F]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Alpha">{@code \p{Alpha}}</th>
+ *     <td headers="matches posix Alpha">An alphabetic character:{@code [\p{IsAlphabetic}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Digit">{@code \p{IsDigit}}</th>
+ *     <td headers="matches posix Digit">A decimal digit: {@code \p{gc=Decimal_Number}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Alnum">{@code \p{Alnum}}</th>
+ *     <td headers="matches posix Alnum">An alphanumeric character:{@code [\p{Alpha}\p{Digit}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Punct">{@code \p{Punct}}</th>
+ *     <td headers="matches posix Punct">Punctuation: {@code \p{IsPunctuation}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Graph">{@code \p{Graph}}</th>
+ *     <td headers="matches posix Graph">A visible character:
+ *     {@code [^p{space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Print">{@code \p{Print}}</th>
+ *     <td headers="matches posix Print">A printable character: {@code [\p{Graph}\p{Blank}&&[^\p{Cntrl}]]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Blank">{@code \p{Blank}}</th>
+ *     <td headers="matches posix Blank">A space or a tab: {@code [\p{gc=Space_Separator}\N{CHARACTER TABULATION}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Cntrl">{@code \p{Cntrl}}</th>
+ *     <td headers="matches posix Cntrl">A control character: {@code \p{gc=Control}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="XDigit">{@code \p{XDigit}}</th>
+ *     <td headers="matches posix XDigit">A hexadecimal digit: {@code [\p{gc=Decimal_Number}\p{IsHex_Digit}]}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Space">{@code \p{Space}}</th>
+ *     <td headers="matches posix Space">A whitespace character: {@code \p{IsWhite_Space}}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="PosixCompatible">POSIX-Compatible expression</th>
+ *     <td headers="matches posix PosixCompatible">See <a href="http://www.unicode.org/reports/tr18/#Compatibility_Properties">Unicode documentation</a></td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="java">java.lang.Character classes (simple <a href="#jcc">java character type</a>)</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="javaLowerCase">{@code \p{javaLowerCase}}</th>
+ *     <td headers="matches java javaLowerCase">Equivalent to java.lang.Character.isLowerCase()</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="javaUpperCase">{@code \p{javaUpperCase}}</th>
+ *     <td headers="matches java javaUpperCase">Equivalent to java.lang.Character.isUpperCase()</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="javaWhitespace">{@code \p{javaWhitespace}}</th>
+ *     <td headers="matches java javaWhitespace">Equivalent to java.lang.Character.isWhitespace()</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="javaMirrored">{@code \p{javaMirrored}}</th>
+ *     <td headers="matches java javaMirrored">Equivalent to java.lang.Character.isMirrored()</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px"  id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="IsLatin">{@code \p{IsLatin}}</th>
+ *     <td headers="matches unicode IsLatin">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="InGreek">{@code \p{InGreek}}</th>
+ *     <td headers="matches unicode InGreek">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Lu">{@code \p{Lu}}</th>
+ *     <td headers="matches unicode Lu">An uppercase letter (<a href="#ucc">category</a>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="IsAlphabetic">{@code \p{IsAlphabetic}}</th>
+ *     <td headers="matches unicode IsAlphabetic">An alphabetic character (<a href="#ubpc">binary property</a>)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="Sc">{@code \p{Sc}}</th>
+ *     <td headers="matches unicode Sc">A currency symbol</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="not_InGreek">{@code \P{InGreek}}</th>
+ *     <td headers="matches unicode not_InGreek">Any character except one in the Greek block (negation)</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="not_uppercase">{@code [\p{L}&&[^\p{Lu}]]}</th>
+ *     <td headers="matches unicode not_uppercase">Any letter except an uppercase letter (subtraction)</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="bounds">Boundary matchers</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="begin_line">{@code ^}</th>
+ *     <td headers="matches bounds begin_line">The beginning of a line</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="end_line">{@code $}</th>
+ *     <td headers="matches bounds end_line">The end of a line</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="word_boundary">{@code \b}</th>
+ *     <td headers="matches bounds word_boundary">A word boundary</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_word_boundary">{@code \B}</th>
+ *     <td headers="matches bounds non_word_boundary">A non-word boundary</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="begin_input">{@code \A}</th>
+ *     <td headers="matches bounds begin_input">The beginning of the input</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="end_prev_match">{@code \G}</th>
+ *     <td headers="matches bounds end_prev_match">The end of the previous match</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="end_input_except_term">{@code \Z}</th>
+ *     <td headers="matches bounds end_input_except_term">The end of the input but for the final
+ *         <a href="#lt">terminator</a>, if&nbsp;any</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="end_input">{@code \z}</th>
+ *     <td headers="matches bounds end_input">The end of the input</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="linebreak">Linebreak matcher</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="any_unicode_linebreak">{@code \R}</th>
+ *     <td headers="matches linebreak any_unicode_linebreak">Any Unicode linebreak sequence, is equivalent to
+ *     <code>&#92;u000D&#92;u000A|[&#92;u000A&#92;u000B&#92;u000C&#92;u000D&#92;u0085&#92;u2028&#92;u2029]
+ *     </code></td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="grapheme">Unicode Extended Grapheme matcher</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="grapheme_any">{@code \X}</th>
+ *     <td headers="matches grapheme grapheme_any">Any Unicode extended grapheme cluster</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="greedy">Greedy quantifiers</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_once_or_not"><i>X</i>{@code ?}</th>
+ *     <td headers="matches greedy greedy_once_or_not"><i>X</i>, once or not at all</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_zero_or_more"><i>X</i>{@code *}</th>
+ *     <td headers="matches greedy greedy_zero_or_more"><i>X</i>, zero or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_one_or_more"><i>X</i>{@code +}</th>
+ *     <td headers="matches greedy greedy_one_or_more"><i>X</i>, one or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_exactly"><i>X</i><code>{</code><i>n</i><code>}</code></th>
+ *     <td headers="matches greedy greedy_exactly"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_at_least"><i>X</i><code>{</code><i>n</i>{@code ,}}</th>
+ *     <td headers="matches greedy greedy_at_least"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="greedy_at_least_up_to"><i>X</i><code>{</code><i>n</i>{@code ,}<i>m</i><code>}</code></th>
+ *     <td headers="matches greedy greedy_at_least_up_to"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="reluc">Reluctant quantifiers</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_once_or_not"><i>X</i>{@code ??}</th>
+ *     <td headers="matches reluc reluc_once_or_not"><i>X</i>, once or not at all</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_zero_or_more"><i>X</i>{@code *?}</th>
+ *     <td headers="matches reluc reluc_zero_or_more"><i>X</i>, zero or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_one_or_more"><i>X</i>{@code +?}</th>
+ *     <td headers="matches reluc reluc_one_or_more"><i>X</i>, one or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_exactly"><i>X</i><code>{</code><i>n</i><code>}?</code></th>
+ *     <td headers="matches reluc reluc_exactly"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_at_least"><i>X</i><code>{</code><i>n</i><code>,}?</code></th>
+ *     <td headers="matches reluc reluc_at_least"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="reluc_at_least_up_to"><i>X</i><code>{</code><i>n</i>{@code ,}<i>m</i><code>}?</code></th>
+ *     <td headers="matches reluc reluc_at_least_up_to"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="poss">Possessive quantifiers</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_once_or_not"><i>X</i>{@code ?+}</th>
+ *     <td headers="matches poss poss_once_or_not"><i>X</i>, once or not at all</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_zero_or_more"><i>X</i>{@code *+}</th>
+ *     <td headers="matches poss poss_zero_or_more"><i>X</i>, zero or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_one_or_more"><i>X</i>{@code ++}</th>
+ *     <td headers="matches poss poss_one_or_more"><i>X</i>, one or more times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_exactly"><i>X</i><code>{</code><i>n</i><code>}+</code></th>
+ *     <td headers="matches poss poss_exactly"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_at_least"><i>X</i><code>{</code><i>n</i><code>,}+</code></th>
+ *     <td headers="matches poss poss_at_least"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="poss_at_least_up_to"><i>X</i><code>{</code><i>n</i>{@code ,}<i>m</i><code>}+</code></th>
+ *     <td headers="matches poss poss_at_least_up_to"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="logical">Logical operators</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="concat"><i>XY</i></th>
+ *     <td headers="matches logical concat"><i>X</i> followed by <i>Y</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="alternate"><i>X</i>{@code |}<i>Y</i></th>
+ *     <td headers="matches logical alternate">Either <i>X</i> or <i>Y</i></td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="group">{@code (}<i>X</i>{@code )}</th>
+ *     <td headers="matches logical group">X, as a <a href="#cg">capturing group</a></td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="backref">Back references</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="back_nth">{@code \}<i>n</i></th>
+ *     <td headers="matches backref back_nth">Whatever the <i>n</i><sup>th</sup>
+ *     <a href="#cg">capturing group</a> matched</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="back_named">{@code \}<i>k</i>&lt;<i>name</i>&gt;</th>
+ *     <td headers="matches backref back_named">Whatever the
+ *     <a href="#groupname">named-capturing group</a> "name" matched. Only available for API 26 or above</td></tr>
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="quote">Quotation</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="quote_follow">{@code \}</th>
+ *     <td headers="matches quote quote_follow">Nothing, but quotes the following character</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="quote_begin">{@code \Q}</th>
+ *     <td headers="matches quote quote_begin">Nothing, but quotes all characters until {@code \E}</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="quote_end">{@code \E}</th>
+ *     <td headers="matches quote quote_end">Nothing, but ends quoting started by {@code \Q}</td></tr>
+ *     <!-- Metachars: !$()*+.<>?[\]^{|} -->
+ *
+ * <tr><th colspan="2" style="padding-top:20px" id="special">Special constructs (named-capturing and non-capturing)</th></tr>
+ *
+ * <tr><th style="vertical-align:top; font-weight:normal" id="named_group"><code>(?&lt;<a href="#groupname">name</a>&gt;</code><i>X</i>{@code )}</th>
+ *     <td headers="matches special named_group"><i>X</i>, as a named-capturing group. Only available for API 26 or above.</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_capture_group">{@code (?:}<i>X</i>{@code )}</th>
+ *     <td headers="matches special non_capture_group"><i>X</i>, as a non-capturing group</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="flags"><code>(?idmsux-idmsux)&nbsp;</code></th>
+ * <a href="#UNIX_LINES">d</a> <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a>
+ * <a href="#UNICODE_CASE">u</a> <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a>
+ * on - off</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="non_capture_group_flags">{@code (?idmsuxU-idmsuxU:}<i>X</i>{@code )}&nbsp;&nbsp;</th>
+ *     <td headers="matches special non_capture_group_flags"><i>X</i>, as a <a href="#cg">non-capturing group</a> with the
+ *         given flags <a href="#CASE_INSENSITIVE">i</a> <a href="#UNIX_LINES">d</a>
+ * <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a> <a href="#UNICODE_CASE">u</a >
+ * <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a> on - off</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="pos_lookahead">{@code (?=}<i>X</i>{@code )}</th>
+ *     <td headers="matches special pos_lookahead"><i>X</i>, via zero-width positive lookahead</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="neg_lookahead">{@code (?!}<i>X</i>{@code )}</th>
+ *     <td headers="matches special neg_lookahead"><i>X</i>, via zero-width negative lookahead</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="pos_lookbehind">{@code (?<=}<i>X</i>{@code )}</th>
+ *     <td headers="matches special pos_lookbehind"><i>X</i>, via zero-width positive lookbehind</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="neg_lookbehind">{@code (?<!}<i>X</i>{@code )}</th>
+ *     <td headers="matches special neg_lookbehind"><i>X</i>, via zero-width negative lookbehind</td></tr>
+ * <tr><th style="vertical-align:top; font-weight:normal" id="indep_non_capture_group">{@code (?>}<i>X</i>{@code )}</th>
+ *     <td headers="matches special indep_non_capture_group"><i>X</i>, as an independent, non-capturing group</td></tr>
+ *
+ * </tbody>
+ * </table>
+ *
+ * <hr>
+ *
+ *
+ * <h2><a id="bs">Backslashes, escapes, and quoting</a></h2>
+ *
+ * <p> The backslash character ({@code '\'}) serves to introduce escaped
+ * constructs, as defined in the table above, as well as to quote characters
+ * that otherwise would be interpreted as unescaped constructs.  Thus the
+ * expression {@code \\} matches a single backslash and <code>\{</code> matches a
+ * left brace.
+ *
+ * <p> It is an error to use a backslash prior to any alphabetic character that
+ * does not denote an escaped construct; these are reserved for future
+ * extensions to the regular-expression language.  A backslash may be used
+ * prior to a non-alphabetic character regardless of whether that character is
+ * part of an unescaped construct.
+ *
+ * <p> Backslashes within string literals in Java source code are interpreted
+ * as required by
+ * <cite>The Java Language Specification</cite>
+ * as either Unicode escapes (section {@jls 3.3}) or other character escapes (section {@jls 3.10.6})
+ * It is therefore necessary to double backslashes in string
+ * literals that represent regular expressions to protect them from
+ * interpretation by the Java bytecode compiler.  The string literal
+ * <code>"&#92;b"</code>, for example, matches a single backspace character when
+ * interpreted as a regular expression, while {@code "\\b"} matches a
+ * word boundary.  The string literal {@code "\(hello\)"} is illegal
+ * and leads to a compile-time error; in order to match the string
+ * {@code (hello)} the string literal {@code "\\(hello\\)"}
+ * must be used.
+ *
+ * <h2><a id="cc">Character Classes</a></h2>
+ *
+ *    <p> Character classes may appear within other character classes, and
+ *    may be composed by the union operator (implicit) and the intersection
+ *    operator ({@code &&}).
+ *    The union operator denotes a class that contains every character that is
+ *    in at least one of its operand classes.  The intersection operator
+ *    denotes a class that contains every character that is in both of its
+ *    operand classes.
+ *
+ *    <p> The precedence of character-class operators is as follows, from
+ *    highest to lowest:
+ *
+ *    <table class="striped" style="margin-left: 2em;">
+ *      <caption style="display:none">Precedence of character class operators.</caption>
+ *      <thead>
+ *      <tr><th scope="col">Precedence<th scope="col">Name<th scope="col">Example
+ *      </thead>
+ *      <tbody>
+ *      <tr><th scope="row">1</th>
+ *        <td>Literal escape&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ *        <td>{@code \x}</td></tr>
+ *     <tr><th scope="row">2</th>
+ *        <td>Grouping</td>
+ *        <td>{@code [...]}</td></tr>
+ *     <tr><th scope="row">3</th>
+ *        <td>Range</td>
+ *        <td>{@code a-z}</td></tr>
+ *      <tr><th scope="row">4</th>
+ *        <td>Union</td>
+ *        <td>{@code [a-e][i-u]}</td></tr>
+ *      <tr><th scope="row">5</th>
+ *        <td>Intersection</td>
+ *        <td>{@code [a-z&&[aeiou]]}</td></tr>
+ *      </tbody>
+ *    </table>
+ *
+ *    <p> Note that a different set of metacharacters are in effect inside
+ *    a character class than outside a character class. For instance, the
+ *    regular expression {@code .} loses its special meaning inside a
+ *    character class, while the expression {@code -} becomes a range
+ *    forming metacharacter.
+ *
+ * <h2><a id="lt">Line terminators</a></h2>
+ *
+ * <p> A <i>line terminator</i> is a one- or two-character sequence that marks
+ * the end of a line of the input character sequence.  The following are
+ * recognized as line terminators:
+ *
+ * <ul>
+ *
+ *   <li> A newline (line feed) character ({@code '\n'}),
+ *
+ *   <li> A carriage-return character followed immediately by a newline
+ *   character ({@code "\r\n"}),
+ *
+ *   <li> A standalone carriage-return character ({@code '\r'}),
+ *
+ *   <li> A next-line character (<code>'&#92;u0085'</code>),
+ *
+ *   <li> A line-separator character (<code>'&#92;u2028'</code>), or
+ *
+ *   <li> A paragraph-separator character (<code>'&#92;u2029'</code>).
+ *
+ * </ul>
+ * <p>If {@link #UNIX_LINES} mode is activated, then the only line terminators
+ * recognized are newline characters.
+ *
+ * <p> The regular expression {@code .} matches any character except a line
+ * terminator unless the {@link #DOTALL} flag is specified.
+ *
+ * <p> By default, the regular expressions {@code ^} and {@code $} ignore
+ * line terminators and only match at the beginning and the end, respectively,
+ * of the entire input sequence. If {@link #MULTILINE} mode is activated then
+ * {@code ^} matches at the beginning of input and after any line terminator
+ * except at the end of input. When in {@link #MULTILINE} mode {@code $}
+ * matches just before a line terminator or the end of the input sequence.
+ *
+ * <h2><a id="cg">Groups and capturing</a></h2>
+ *
+ * <h3><a id="gnumber">Group number</a></h3>
+ * <p> Capturing groups are numbered by counting their opening parentheses from
+ * left to right.  In the expression {@code ((A)(B(C)))}, for example, there
+ * are four such groups: </p>
+ *
+ * <ol style="margin-left:2em;">
+ *   <li> {@code ((A)(B(C)))}
+ *   <li> {@code (A)}
+ *   <li> {@code (B(C))}
+ *   <li> {@code (C)}
+ * </ol>
+ *
+ * <p> Group zero always stands for the entire expression.
+ *
+ * <p> Capturing groups are so named because, during a match, each subsequence
+ * of the input sequence that matches such a group is saved.  The captured
+ * subsequence may be used later in the expression, via a back reference, and
+ * may also be retrieved from the matcher once the match operation is complete.
+ *
+ * <h3><a id="groupname">Group name</a></h3>
+ * <p>The constructs and APIs are available since API level 26. A capturing group
+ * can also be assigned a "name", a {@code named-capturing group},
+ * and then be back-referenced later by the "name". Group names are composed of
+ * the following characters. The first character must be a {@code letter}.
+ *
+ * <ul>
+ *   <li> The uppercase letters {@code 'A'} through {@code 'Z'}
+ *        (<code>'&#92;u0041'</code>&nbsp;through&nbsp;<code>'&#92;u005a'</code>),
+ *   <li> The lowercase letters {@code 'a'} through {@code 'z'}
+ *        (<code>'&#92;u0061'</code>&nbsp;through&nbsp;<code>'&#92;u007a'</code>),
+ *   <li> The digits {@code '0'} through {@code '9'}
+ *        (<code>'&#92;u0030'</code>&nbsp;through&nbsp;<code>'&#92;u0039'</code>),
+ * </ul>
+ *
+ * <p> A {@code named-capturing group} is still numbered as described in
+ * <a href="#gnumber">Group number</a>.
+ *
+ * <p> The captured input associated with a group is always the subsequence
+ * that the group most recently matched.  If a group is evaluated a second time
+ * because of quantification then its previously-captured value, if any, will
+ * be retained if the second evaluation fails.  Matching the string
+ * {@code "aba"} against the expression {@code (a(b)?)+}, for example, leaves
+ * group two set to {@code "b"}.  All captured input is discarded at the
+ * beginning of each match.
+ *
+ * <p> Groups beginning with {@code (?} are either pure, <i>non-capturing</i> groups
+ * that do not capture text and do not count towards the group total, or
+ * <i>named-capturing</i> group.
+ *
+ * <h2> Unicode support </h2>
+ *
+ * <p> This class is in conformance with Level 1 of <a
+ * href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+ * Standard #18: Unicode Regular Expressions</i></a>, plus RL2.1
+ * Canonical Equivalents and RL2.2 Extended Grapheme Clusters.
+ * <p>
+ * <b>Unicode escape sequences</b> such as <code>&#92;u2014</code> in Java source code
+ * are processed as described in section {@jls 3.3} of
+ * <cite>The Java Language Specification</cite>.
+ * Such escape sequences are also implemented directly by the regular-expression
+ * parser so that Unicode escapes can be used in expressions that are read from
+ * files or from the keyboard.  Thus the strings <code>"&#92;u2014"</code> and
+ * {@code "\\u2014"}, while not equal, compile into the same pattern, which
+ * matches the character with hexadecimal value {@code 0x2014}.
+ * <p>
+ * A Unicode character can also be represented by using its <b>Hex notation</b>
+ * (hexadecimal code point value) directly as described in construct
+ * <code>&#92;x{...}</code>, for example a supplementary character U+2011F can be
+ * specified as <code>&#92;x{2011F}</code>, instead of two consecutive Unicode escape
+ * sequences of the surrogate pair <code>&#92;uD840</code><code>&#92;uDD1F</code>.
+ * <p>
+ * <b>Unicode character names</b> are supported by the named character construct
+ * <code>\N{</code>...<code>}</code>, for example, <code>\N{WHITE SMILING FACE}</code>
+ * specifies character <code>&#92;u263A</code>. The character names supported
+ * by this class are the valid Unicode character names matched by
+ * {@code java.lang.Character.codePointOf(String) Character.codePointOf(name)}.
+ * <p>
+ * <a href="http://www.unicode.org/reports/tr18/#Default_Grapheme_Clusters">
+ * <b>Unicode extended grapheme clusters</b></a> are supported by the grapheme
+ * cluster matcher {@code \X}.
+ * <p>
+ * Unicode scripts, blocks, categories and binary properties are written with
+ * the {@code \p} and {@code \P} constructs as in Perl.
+ * <code>\p{</code><i>prop</i><code>}</code> matches if
+ * the input has the property <i>prop</i>, while <code>\P{</code><i>prop</i><code>}</code>
+ * does not match if the input has that property.
+ * <p>
+ * Scripts, blocks, categories and binary properties can be used both inside
+ * and outside of a character class.
+ *
+ * <p>
+ * <b><a id="usc">Scripts</a></b> are specified either with the prefix {@code Is} supported since
+ * Android 10, as in {@code IsHiragana}, or by using the {@code script} keyword (or its short
+ * form {@code sc}) as in {@code script=Hiragana} or {@code sc=Hiragana}.
+ * <p>
+ * The script names supported by {@code Pattern} are the valid script names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeScript#forName(String) UnicodeScript.forName}.
+ *
+ * <p>
+ * <b><a id="ubc">Blocks</a></b> are specified with the prefix {@code In}, as in
+ * {@code InMongolian}, or by using the keyword {@code block} (or its short
+ * form {@code blk}) as in {@code block=Mongolian} or {@code blk=Mongolian}.
+ * <p>
+ * The block names supported by {@code Pattern} are the valid block names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeBlock#forName(String) UnicodeBlock.forName}.
+ * <p>
+ *
+ * <b><a id="ucc">Categories</a></b> may be specified with the optional prefix {@code Is}:
+ * Both {@code \p{IsL}} supported since Android 10 and {@code \p{L}} denote the category of Unicode
+ * letters. Same as scripts and blocks, categories can also be specified
+ * by using the keyword {@code general_category} (or its short form
+ * {@code gc}) as in {@code general_category=Lu} or {@code gc=Lu}.
+ * <p>
+ * The supported categories are those of
+ * <a href="http://www.unicode.org/standard/standard.html">
+ * <i>The Unicode Standard</i></a> in the version specified by the
+ * {@link java.lang.Character Character} class. The category names are those
+ * defined in the Standard, both normative and informative.
+ * <p>
+ *
+ * <b><a id="ubpc">Binary properties</a></b> are specified with the prefix {@code Is} since
+ * Android 10, as in {@code IsAlphabetic}. The prefix {@code Is} isn't needed before Android 10,
+ * as in {@code Alphabetic}. The supported binary properties by {@code Pattern}
+ * are
+ * <ul>
+ *   <li> Alphabetic
+ *   <li> Ideographic
+ *   <li> Letter
+ *   <li> Lowercase
+ *   <li> Uppercase
+ *   <li> Titlecase
+ *   <li> Punctuation
+ *   <Li> Control
+ *   <li> White_Space
+ *   <li> Digit
+ *   <li> Hex_Digit
+ *   <li> Join_Control
+ *   <li> Noncharacter_Code_Point
+ *   <li> Assigned
+ * </ul>
+ * <p>
+ * The <b>Predefined Character classes</b> and <b>POSIX character classes</b>
+ * are in conformance with the recommendation of <i>Annex C: Compatibility Properties</i>
+ * of <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical Standard #18:
+ * Unicode Regular Expressions</i></a>.
+ *
+ * <p>
+ * <a id="jcc">
+ * Categories that behave like the java.lang.Character
+ * boolean is<i>methodname</i> methods (except for the deprecated ones) are
+ * available through the same <code>\p{</code><i>prop</i><code>}</code> syntax where
+ * the specified property has the name <code>java<i>methodname</i></code></a>.
+ *
+ * <h3> Behavior starting from API level 10 (Android 2.3) </h3>
+ *
+ * <p> Starting from Android 2.3 Gingerbread, ICU4C becomes the backend of the regular expression
+ * implementation. Android could behave differently compared with other regex implementation, e.g.
+ * literal right brace ('}') has to be escaped on Android.</p>
+ *
+ * <p> Some other behavior differences can be found in the
+ * <a href="https://unicode-org.github.io/icu/userguide/strings/regexp.html#differences-with-java-regular-expressions">
+ * ICU documentation</a>. </p>
+ *
+ * <h2> Comparison to Perl 5 </h2>
+ *
+ * <p>The {@code Pattern} engine performs traditional NFA-based matching
+ * with ordered alternation as occurs in Perl 5.
+ *
+ * <p> Perl constructs not supported by this class: </p>
+ *
+ * <ul>
+ *    <li><p> The backreference constructs, <code>\g{</code><i>n</i><code>}</code> for
+ *    the <i>n</i><sup>th</sup><a href="#cg">capturing group</a> and
+ *    <code>\g{</code><i>name</i><code>}</code> for
+ *    <a href="#groupname">named-capturing group</a>.
+ *    </p></li>
+ *
+ *    <li><p> The conditional constructs
+ *    {@code (?(}<i>condition</i>{@code )}<i>X</i>{@code )} and
+ *    {@code (?(}<i>condition</i>{@code )}<i>X</i>{@code |}<i>Y</i>{@code )},
+ *    </p></li>
+ *
+ *    <li><p> The embedded code constructs <code>(?{</code><i>code</i><code>})</code>
+ *    and <code>(??{</code><i>code</i><code>})</code>,</p></li>
+ *
+ *    <li><p> The embedded comment syntax {@code (?#comment)}, and </p></li>
+ *
+ *    <li><p> The preprocessing operations {@code \l} <code>&#92;u</code>,
+ *    {@code \L}, and {@code \U}.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Constructs supported by this class but not by Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> Character-class union and intersection as described
+ *    <a href="#cc">above</a>.</p></li>
+ *
+ * </ul>
+ *
+ * <p> Notable differences from Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> In Perl, {@code \1} through {@code \9} are always interpreted
+ *    as back references; a backslash-escaped number greater than {@code 9} is
+ *    treated as a back reference if at least that many subexpressions exist,
+ *    otherwise it is interpreted, if possible, as an octal escape.  In this
+ *    class octal escapes must always begin with a zero. In this class,
+ *    {@link #compile(String)} throws {@link PatternSyntaxException} for any
+ *    non-existent back references. Please use {@code \Q} and {@code \E} to
+ *    quote any digit literals followed by back references.
+ *    </p></li>
+ *
+ *    <li><p> Perl uses the {@code g} flag to request a match that resumes
+ *    where the last match left off.  This functionality is provided implicitly
+ *    by the {@link Matcher} class: Repeated invocations of the {@link
+ *    Matcher#find find} method will resume where the last match left off,
+ *    unless the matcher is reset.  </p></li>
+ *
+ *    <li><p> In Perl, embedded flags at the top level of an expression affect
+ *    the whole expression.  In this class, embedded flags always take effect
+ *    at the point at which they appear, whether they are at the top level or
+ *    within a group; in the latter case, flags are restored at the end of the
+ *    group just as in Perl.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <p> For a more precise description of the behavior of regular expression
+ * constructs, please see <a href="http://www.oreilly.com/catalog/regex3/">
+ * <i>Mastering Regular Expressions, 3rd Edition</i>, Jeffrey E. F. Friedl,
+ * O'Reilly and Associates, 2006.</a>
+ * </p>
+ *
+ * @see java.lang.String#split(String, int)
+ * @see java.lang.String#split(String)
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ */
+
+public final class Pattern
+    implements java.io.Serializable
+{
+
+    /*
+     * Regular expression modifier values.  Instead of being passed as
+     * arguments, they can also be passed as inline modifiers.
+     * For example, the following statements have the same effect.
+     *
+     *   Pattern p1 = Pattern.compile("abc", Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
+     *   Pattern p2 = Pattern.compile("(?im)abc", 0);
+     */
+
+    /**
+     * Enables Unix lines mode.
+     *
+     * <p> In this mode, only the {@code '\n'} line terminator is recognized
+     * in the behavior of {@code .}, {@code ^}, and {@code $}.
+     *
+     * <p> Unix lines mode can also be enabled via the embedded flag
+     * expression&nbsp;{@code (?d)}.
+     */
+    public static final int UNIX_LINES = 0x01;
+
+    // Android-changed: CASE_INSENSITIVE is Unicode-aware on Android.
+    /**
+     * Enables case-insensitive matching.
+     *
+     * <p> Case-insensitive matching is Unicode-aware on Android.
+     *
+     * <p> Case-insensitive matching can also be enabled via the embedded flag
+     * expression&nbsp;{@code (?i)}.
+     *
+     * <p> Specifying this flag may impose a slight performance penalty.  </p>
+     */
+    public static final int CASE_INSENSITIVE = 0x02;
+
+    /**
+     * Permits whitespace and comments in pattern.
+     *
+     * <p> In this mode, whitespace is ignored, and embedded comments starting
+     * with {@code #} are ignored until the end of a line.
+     *
+     * <p> Comments mode can also be enabled via the embedded flag
+     * expression&nbsp;{@code (?x)}.
+     */
+    public static final int COMMENTS = 0x04;
+
+    /**
+     * Enables multiline mode.
+     *
+     * <p> In multiline mode the expressions {@code ^} and {@code $} match
+     * just after or just before, respectively, a line terminator or the end of
+     * the input sequence.  By default these expressions only match at the
+     * beginning and the end of the entire input sequence.
+     *
+     * <p> Multiline mode can also be enabled via the embedded flag
+     * expression&nbsp;{@code (?m)}.  </p>
+     */
+    public static final int MULTILINE = 0x08;
+
+    /**
+     * Enables literal parsing of the pattern.
+     *
+     * <p> When this flag is specified then the input string that specifies
+     * the pattern is treated as a sequence of literal characters.
+     * Metacharacters or escape sequences in the input sequence will be
+     * given no special meaning.
+     *
+     * <p>The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on
+     * matching when used in conjunction with this flag. The other flags
+     * become superfluous.
+     *
+     * <p> There is no embedded flag character for enabling literal parsing.
+     * @since 1.5
+     */
+    public static final int LITERAL = 0x10;
+
+    /**
+     * Enables dotall mode.
+     *
+     * <p> In dotall mode, the expression {@code .} matches any character,
+     * including a line terminator.  By default this expression does not match
+     * line terminators.
+     *
+     * <p> Dotall mode can also be enabled via the embedded flag
+     * expression&nbsp;{@code (?s)}.  (The {@code s} is a mnemonic for
+     * "single-line" mode, which is what this is called in Perl.)  </p>
+     */
+    public static final int DOTALL = 0x20;
+
+    // Android-changed: UNICODE_CASE flag is ignored.
+    /**
+     * Enables Unicode-aware case folding. This flag is ignoredon Android.
+     * When {@link #CASE_INSENSITIVE} flag is provided, case-insensitive
+     * matching is always done in a manner consistent with the Unicode Standard.
+     *
+     * <p> The embedded flag &nbsp;{@code (?u)} is ignored.
+     *
+     * <p> Specifying this flag may impose a performance penalty.  </p>
+     */
+    public static final int UNICODE_CASE = 0x40;
+
+    // Android-changed: Android does not support CANON_EQ flag.
+    /**
+     * This flag is not supported on Android.
+     */
+    public static final int CANON_EQ = 0x80;
+
+    // Android-changed: Android always uses unicode character classes.
+    /**
+     * This flag is not supported on Android, and Unicode character classes are always
+     * used.
+     * <p>
+     * See the Unicode version of
+     * <i>Predefined character classes</i> and <i>POSIX character classes</i>
+     * are in conformance with
+     * <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+     * Standard #18: Unicode Regular Expressions</i></a>
+     * <i>Annex C: Compatibility Properties</i>.
+     * <p>
+     * @since 1.7
+     */
+    public static final int UNICODE_CHARACTER_CLASS = 0x100;
+
+    /**
+     * Contains all possible flags for compile(regex, flags).
+     */
+    private static final int ALL_FLAGS = CASE_INSENSITIVE | MULTILINE |
+            // Android-changed: CANON_EQ and UNICODE_CHARACTER_CLASS flags aren't supported.
+            // DOTALL | UNICODE_CASE | CANON_EQ | UNIX_LINES | LITERAL |
+            // UNICODE_CHARACTER_CLASS | COMMENTS;
+            DOTALL | UNICODE_CASE | UNIX_LINES | LITERAL | COMMENTS;
+
+    /* Pattern has only two serialized components: The pattern string
+     * and the flags, which are all that is needed to recompile the pattern
+     * when it is deserialized.
+     */
+
+    /** use serialVersionUID from Merlin b59 for interoperability */
+    @java.io.Serial
+    private static final long serialVersionUID = 5073258162644648461L;
+
+    /**
+     * The original regular-expression pattern string.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private String pattern;
+    private final String pattern;
+
+    /**
+     * The original pattern flags.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private int flags;
+    private final int flags;
+
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // We only need some tie-ins to native memory, instead of a large number
+    // of fields on the .java side.
+    /* package */ transient PatternNative nativePattern;
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    /**
+     * Compiles the given regular expression into a pattern.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     * @return the given regular expression compiled into a pattern
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex) {
+        return new Pattern(regex, 0);
+    }
+
+    // Android-changed: Android doesn't support CANON_EQ and UNICODE_CHARACTER_CLASS flags.
+    /**
+     * Compiles the given regular expression into a pattern with the given
+     * flags.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  flags
+     *         Match flags, a bit mask that may include
+     *         {@link #CASE_INSENSITIVE}, {@link #MULTILINE}, {@link #DOTALL},
+     *         {@link #UNICODE_CASE}, {@link #UNIX_LINES}, {@link #LITERAL},
+     *         and {@link #COMMENTS}
+     *
+     * @return the given regular expression compiled into a pattern with the given flags
+     * @throws  IllegalArgumentException
+     *          If bit values other than those corresponding to the defined
+     *          match flags are set in {@code flags}
+     *
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex, int flags) {
+        return new Pattern(regex, flags);
+    }
+
+    /**
+     * Returns the regular expression from which this pattern was compiled.
+     *
+     * @return  The source of this pattern
+     */
+    public String pattern() {
+        return pattern;
+    }
+
+    /**
+     * <p>Returns the string representation of this pattern. This
+     * is the regular expression from which this pattern was
+     * compiled.</p>
+     *
+     * @return  The string representation of this pattern
+     * @since 1.5
+     */
+    public String toString() {
+        return pattern;
+    }
+
+    /**
+     * Creates a matcher that will match the given input against this pattern.
+     *
+     * @param  input
+     *         The character sequence to be matched
+     *
+     * @return  A new matcher for this pattern
+     */
+    public Matcher matcher(CharSequence input) {
+        // Android-removed: Pattern is eagerly compiled() upon construction.
+        /*
+        if (!compiled) {
+            synchronized(this) {
+                if (!compiled)
+                    compile();
+            }
+        }
+        */
+        Matcher m = new Matcher(this, input);
+        return m;
+    }
+
+    /**
+     * Returns this pattern's match flags.
+     *
+     * @return  The match flags specified when this pattern was compiled
+     */
+    public int flags() {
+        // Android-changed: We don't need the temporary pattern flags0.
+        // return flags0;
+        return flags;
+    }
+
+    /**
+     * Compiles the given regular expression and attempts to match the given
+     * input against it.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><pre>
+     * Pattern.matches(regex, input);</pre></blockquote>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>
+     * Pattern.compile(regex).matcher(input).matches()</pre></blockquote>
+     *
+     * <p> If a pattern is to be used multiple times, compiling it once and reusing
+     * it will be more efficient than invoking this method each time.  </p>
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  input
+     *         The character sequence to be matched
+     * @return whether or not the regular expression matches on the input
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static boolean matches(String regex, CharSequence input) {
+        Pattern p = Pattern.compile(regex);
+        Matcher m = p.matcher(input);
+        return m.matches();
+    }
+
+    // Android-changed: Adopt split() behavior change only for apps targeting API > 28.
+    // http://b/109659282#comment7
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> The array returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the array are in the order in which they occur in the
+     * input. If this pattern does not match any subsequence of the input then
+     * the resulting array has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the resulting array. A zero-width match at the beginning however
+     * can only produce such an empty leading substring for apps running on or
+     * targeting API versions <= 28.
+     *
+     * <p> The {@code limit} parameter controls the number of times the
+     * pattern is applied and therefore affects the length of the resulting
+     * array.
+     * <ul>
+     *    <li><p>
+     *    If the <i>limit</i> is positive then the pattern will be applied
+     *    at most <i>limit</i>&nbsp;-&nbsp;1 times, the array's length will be
+     *    no greater than <i>limit</i>, and the array's last entry will contain
+     *    all input beyond the last matched delimiter.</p></li>
+     *
+     *    <li><p>
+     *    If the <i>limit</i> is zero then the pattern will be applied as
+     *    many times as possible, the array can have any length, and trailing
+     *    empty strings will be discarded.</p></li>
+     *
+     *    <li><p>
+     *    If the <i>limit</i> is negative then the pattern will be applied
+     *    as many times as possible and the array can have any length.</p></li>
+     * </ul>
+     *
+     * <p> The input {@code "boo:and:foo"}, for example, yields the following
+     * results with these parameters:
+     *
+     * <table class="plain" style="margin-left:2em;">
+     * <caption style="display:none">Split example showing regex, limit, and result</caption>
+     * <thead>
+     * <tr>
+     *     <th scope="col">Regex</th>
+     *     <th scope="col">Limit</th>
+     *     <th scope="col">Result</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr><th scope="row" rowspan="3" style="font-weight:normal">:</th>
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">2</th>
+     *     <td>{@code { "boo", "and:foo" }}</td></tr>
+     * <tr><!-- : -->
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">5</th>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><!-- : -->
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">-2</th>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><th scope="row" rowspan="3" style="font-weight:normal">o</th>
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">5</th>
+     *     <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
+     * <tr><!-- o -->
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">-2</th>
+     *     <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
+     * <tr><!-- o -->
+     *     <th scope="row" style="font-weight:normal; text-align:right; padding-right:1em">0</th>
+     *     <td>{@code { "b", "", ":and:f" }}</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @param  limit
+     *         The result threshold, as described above
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input, int limit) {
+        // BEGIN Android-added: fastSplit() to speed up simple cases.
+        String[] fast = fastSplit(pattern, input.toString(), limit);
+        if (fast != null) {
+            return fast;
+        }
+        // END Android-added: fastSplit() to speed up simple cases.
+        int index = 0;
+        boolean matchLimited = limit > 0;
+        ArrayList<String> matchList = new ArrayList<>();
+        Matcher m = matcher(input);
+
+        // Add segments before each match found
+        while(m.find()) {
+            if (!matchLimited || matchList.size() < limit - 1) {
+                if (index == 0 && index == m.start() && m.start() == m.end()) {
+                    // no empty leading substring included for zero-width match
+                    // at the beginning of the input char sequence.
+                    // BEGIN Android-changed: split() compat behavior for apps targeting <= 28.
+                    // continue;
+                    int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+                    if (targetSdkVersion > 28) {
+                        continue;
+                    }
+                    // END Android-changed: split() compat behavior for apps targeting <= 28.
+                }
+                String match = input.subSequence(index, m.start()).toString();
+                matchList.add(match);
+                index = m.end();
+            } else if (matchList.size() == limit - 1) { // last one
+                String match = input.subSequence(index,
+                                                 input.length()).toString();
+                matchList.add(match);
+                index = m.end();
+            }
+        }
+
+        // If no match was found, return this
+        if (index == 0)
+            return new String[] {input.toString()};
+
+        // Add remaining segment
+        if (!matchLimited || matchList.size() < limit)
+            matchList.add(input.subSequence(index, input.length()).toString());
+
+        // Construct result
+        int resultSize = matchList.size();
+        if (limit == 0)
+            while (resultSize > 0 && matchList.get(resultSize-1).isEmpty())
+                resultSize--;
+        String[] result = new String[resultSize];
+        return matchList.subList(0, resultSize).toArray(result);
+    }
+
+    // BEGIN Android-added: fastSplit() to speed up simple cases.
+    private static final String FASTSPLIT_METACHARACTERS = "\\?*+[](){}^$.|";
+
+    /**
+     * Returns a result equivalent to {@code s.split(separator, limit)} if it's able
+     * to compute it more cheaply than native impl, or null if the caller should fall back to
+     * using native impl.
+     *
+     *  fastpath will work  if the regex is a
+     *   (1)one-char String and this character is not one of the
+     *      RegEx's meta characters ".$|()[{^?*+\\", or
+     *   (2)two-char String and the first char is the backslash and
+     *      the second is one of regEx's meta characters ".$|()[{^?*+\\".
+     * @hide
+     */
+    public static String[] fastSplit(String re, String input, int limit) {
+        // Can we do it cheaply?
+        int len = re.length();
+        if (len == 0) {
+            return null;
+        }
+        char ch = re.charAt(0);
+        if (len == 1) {
+            if (Character.isSurrogate(ch)) {
+                // Single surrogate is an invalid UTF-16 sequence.
+                return null;
+            } else if (FASTSPLIT_METACHARACTERS.indexOf(ch) != -1) {
+                // We don't allow a single metacharacter.
+                return null;
+            }
+            // pass through
+        } else if (len == 2 && ch == '\\') {
+            // We're looking for a quoted character.
+            // Quoted metacharacters are effectively single non-metacharacters.
+            ch = re.charAt(1);
+            if (FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+
+        // We can do this cheaply...
+
+        // Unlike Perl, which considers the result of splitting the empty string to be the empty
+        // array, Java returns an array containing the empty string.
+        if (input.isEmpty()) {
+            return new String[] { "" };
+        }
+
+        // Count separators
+        int separatorCount = 0;
+        int begin = 0;
+        int end;
+        while (separatorCount + 1 != limit && (end = input.indexOf(ch, begin)) != -1) {
+            ++separatorCount;
+            begin = end + 1;
+        }
+        int lastPartEnd = input.length();
+        if (limit == 0 && begin == lastPartEnd) {
+            // Last part is empty for limit == 0, remove all trailing empty matches.
+            if (separatorCount == lastPartEnd) {
+                // Input contains only separators.
+                return EmptyArray.STRING;
+            }
+            // Find the beginning of trailing separators.
+            do {
+                --begin;
+            } while (input.charAt(begin - 1) == ch);
+            // Reduce separatorCount and fix lastPartEnd.
+            separatorCount -= input.length() - begin;
+            lastPartEnd = begin;
+        }
+
+        // Collect the result parts.
+        String[] result = new String[separatorCount + 1];
+        begin = 0;
+        for (int i = 0; i != separatorCount; ++i) {
+            end = input.indexOf(ch, begin);
+            result[i] = input.substring(begin, end);
+            begin = end + 1;
+        }
+        // Add last part.
+        result[separatorCount] = input.substring(begin, lastPartEnd);
+        return result;
+    }
+    // END Android-added: fastSplit() to speed up simple cases.
+
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> This method works as if by invoking the two-argument {@link
+     * #split(java.lang.CharSequence, int) split} method with the given input
+     * sequence and a limit argument of zero.  Trailing empty strings are
+     * therefore not included in the resulting array. </p>
+     *
+     * <p> The input {@code "boo:and:foo"}, for example, yields the following
+     * results with these expressions:
+     *
+     * <table class="plain" style="margin-left:2em">
+     * <caption style="display:none">Split examples showing regex and result</caption>
+     * <thead>
+     * <tr>
+     *  <th scope="col">Regex</th>
+     *  <th scope="col">Result</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr><th scope="row" style="text-weight:normal">:</th>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><th scope="row" style="text-weight:normal">o</th>
+     *     <td>{@code { "b", "", ":and:f" }}</td></tr>
+     * </tbody>
+     * </table>
+     *
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input) {
+        return split(input, 0);
+    }
+
+    /**
+     * Returns a literal pattern {@code String} for the specified
+     * {@code String}.
+     *
+     * <p>This method produces a {@code String} that can be used to
+     * create a {@code Pattern} that would match the string
+     * {@code s} as if it were a literal pattern.</p> Metacharacters
+     * or escape sequences in the input sequence will be given no special
+     * meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quote(String s) {
+        int slashEIndex = s.indexOf("\\E");
+        if (slashEIndex == -1)
+            return "\\Q" + s + "\\E";
+
+        int lenHint = s.length();
+        lenHint = (lenHint < Integer.MAX_VALUE - 8 - lenHint) ?
+                (lenHint << 1) : (Integer.MAX_VALUE - 8);
+
+        StringBuilder sb = new StringBuilder(lenHint);
+        sb.append("\\Q");
+        int current = 0;
+        do {
+            sb.append(s, current, slashEIndex)
+                    .append("\\E\\\\E\\Q");
+            current = slashEIndex + 2;
+        } while ((slashEIndex = s.indexOf("\\E", current)) != -1);
+
+        return sb.append(s, current, s.length())
+                .append("\\E")
+                .toString();
+    }
+
+    /**
+     * Recompile the Pattern instance from a stream.  The original pattern
+     * string is read in and the object tree is recompiled from it.
+     */
+    @java.io.Serial
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in all fields
+        s.defaultReadObject();
+
+        // Android-removed: reimplement matching logic natively via ICU.
+        /*
+        // reset the flags
+        flags0 = flags;
+
+        // Initialize counts
+        capturingGroupCount = 1;
+        localCount = 0;
+        localTCNCount = 0;
+        */
+
+        // Android-changed: Pattern is eagerly compiled() upon construction.
+        /*
+        // if length > 0, the Pattern is lazily compiled
+        if (pattern.isEmpty()) {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+            compiled = true;
+        }
+        */
+        compile();
+    }
+
+    // Android-changed: reimplement matching logic natively via ICU.
+    // Dropped documentation reference to Start and LastNode implementation
+    // details which do not apply on Android.
+    /**
+     * This private constructor is used to create all Patterns. The pattern
+     * string and match flags are all that is needed to completely describe
+     * a Pattern.
+     */
+    private Pattern(String p, int f) {
+        // BEGIN Android-added: CANON_EQ and UNICODE_CHARACTER_CLASS flags are not supported.
+        if ((f & CANON_EQ) != 0) {
+            throw new IllegalArgumentException("CANON_EQ flag isn't supported");
+        }
+        if ((f & UNICODE_CHARACTER_CLASS) != 0) {
+            throw new IllegalArgumentException("UNICODE_CHARACTER_CLASS flag not supported");
+        }
+        // END Android-added: CANON_EQ and UNICODE_CHARACTER_CLASS flags are not supported.
+        if ((f & ~ALL_FLAGS) != 0) {
+            throw new IllegalArgumentException("Unknown flag 0x"
+                                               + Integer.toHexString(f));
+        }
+        pattern = p;
+        flags = f;
+
+        // Android-changed: Pattern is eagerly compiled() upon construction.
+        // BEGIN Android-changed: Reimplement matching logic via ICU4C, and shouldn't overflow.
+        /*
+        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
+        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
+            flags |= UNICODE_CASE;
+
+        // 'flags' for compiling
+        flags0 = flags;
+
+        // Reset group index count
+        capturingGroupCount = 1;
+        localCount = 0;
+        localTCNCount = 0;
+
+        if (!pattern.isEmpty()) {
+            try {
+                compile();
+            } catch (StackOverflowError soe) {
+                throw error("Stack overflow during pattern compilation");
+            }
+        } else {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+        }
+        */
+        compile();
+        // END Android-changed: Reimplement matching logic via ICU4C, and shouldn't overflow.
+    }
+
+    // BEGIN Android-removed: Reimplement matching logic via ICU4C.
+    /**
+     * The pattern is converted to normalized form ({@link
+     * java.text.Normalizer.Form#NFC NFC}, canonical decomposition,
+     * followed by canonical composition for the character class
+     * part, and {@link java.text.Normalizer.Form#NFD NFD},
+     * canonical decomposition for the rest), and then a pure
+     * group is constructed to match canonical equivalences of the
+     * characters.
+     *
+    private static String normalize(String pattern) {
+        int plen = pattern.length();
+        StringBuilder pbuf = new StringBuilder(plen);
+        char last = 0;
+        int lastStart = 0;
+        char cc = 0;
+        for (int i = 0; i < plen;) {
+            char c = pattern.charAt(i);
+            if (cc == 0 &&    // top level
+                c == '\\' && i + 1 < plen && pattern.charAt(i + 1) == '\\') {
+                i += 2; last = 0;
+                continue;
+            }
+            if (c == '[' && last != '\\') {
+                if (cc == 0) {
+                    if (lastStart < i)
+                        normalizeSlice(pattern, lastStart, i, pbuf);
+                    lastStart = i;
+                }
+                cc++;
+            } else if (c == ']' && last != '\\') {
+                cc--;
+                if (cc == 0) {
+                    normalizeClazz(pattern, lastStart, i + 1, pbuf);
+                    lastStart = i + 1;
+                }
+            }
+            last = c;
+            i++;
+        }
+        assert (cc == 0);
+        if (lastStart < plen)
+            normalizeSlice(pattern, lastStart, plen, pbuf);
+        return pbuf.toString();
+    }
+
+    private static void normalizeSlice(String src, int off, int limit,
+                                       StringBuilder dst)
+    {
+        int len = src.length();
+        int off0 = off;
+        while (off < limit && ASCII.isAscii(src.charAt(off))) {
+            off++;
+        }
+        if (off == limit) {
+            dst.append(src, off0, limit);
+            return;
+        }
+        off--;
+        if (off < off0)
+            off = off0;
+        else
+            dst.append(src, off0, off);
+        while (off < limit) {
+            int ch0 = src.codePointAt(off);
+            if (".$|()[]{}^?*+\\".indexOf(ch0) != -1) {
+                dst.append((char)ch0);
+                off++;
+                continue;
+            }
+            int j = Grapheme.nextBoundary(src, off, limit);
+            int ch1;
+            String seq = src.substring(off, j);
+            String nfd = Normalizer.normalize(seq, Normalizer.Form.NFD);
+            off = j;
+            if (nfd.codePointCount(0, nfd.length()) > 1) {
+                ch0 = nfd.codePointAt(0);
+                ch1 = nfd.codePointAt(Character.charCount(ch0));
+                if (Character.getType(ch1) == Character.NON_SPACING_MARK) {
+                    Set<String> altns = new LinkedHashSet<>();
+                    altns.add(seq);
+                    produceEquivalentAlternation(nfd, altns);
+                    dst.append("(?:");
+                    altns.forEach( s -> dst.append(s).append('|'));
+                    dst.delete(dst.length() - 1, dst.length());
+                    dst.append(")");
+                    continue;
+                }
+            }
+            String nfc = Normalizer.normalize(seq, Normalizer.Form.NFC);
+            if (!seq.equals(nfc) && !nfd.equals(nfc))
+                dst.append("(?:" + seq + "|" + nfd  + "|" + nfc + ")");
+            else if (!seq.equals(nfd))
+                dst.append("(?:" + seq + "|" + nfd + ")");
+            else
+                dst.append(seq);
+        }
+    }
+
+    private static void normalizeClazz(String src, int off, int limit,
+                                       StringBuilder dst)
+    {
+        dst.append(Normalizer.normalize(src.substring(off, limit), Form.NFC));
+    }
+
+    /**
+     * Given a specific sequence composed of a regular character and
+     * combining marks that follow it, produce the alternation that will
+     * match all canonical equivalences of that sequence.
+     *
+    private static void produceEquivalentAlternation(String src,
+                                                     Set<String> dst)
+    {
+        int len = countChars(src, 0, 1);
+        if (src.length() == len) {
+            dst.add(src);  // source has one character.
+            return;
+        }
+        String base = src.substring(0,len);
+        String combiningMarks = src.substring(len);
+        String[] perms = producePermutations(combiningMarks);
+        // Add combined permutations
+        for(int x = 0; x < perms.length; x++) {
+            String next = base + perms[x];
+            dst.add(next);
+            next = composeOneStep(next);
+            if (next != null) {
+                produceEquivalentAlternation(next, dst);
+            }
+        }
+    }
+
+    /**
+     * Returns an array of strings that have all the possible
+     * permutations of the characters in the input string.
+     * This is used to get a list of all possible orderings
+     * of a set of combining marks. Note that some of the permutations
+     * are invalid because of combining class collisions, and these
+     * possibilities must be removed because they are not canonically
+     * equivalent.
+     *
+    private static String[] producePermutations(String input) {
+        if (input.length() == countChars(input, 0, 1))
+            return new String[] {input};
+
+        if (input.length() == countChars(input, 0, 2)) {
+            int c0 = Character.codePointAt(input, 0);
+            int c1 = Character.codePointAt(input, Character.charCount(c0));
+            if (getClass(c1) == getClass(c0)) {
+                return new String[] {input};
+            }
+            String[] result = new String[2];
+            result[0] = input;
+            StringBuilder sb = new StringBuilder(2);
+            sb.appendCodePoint(c1);
+            sb.appendCodePoint(c0);
+            result[1] = sb.toString();
+            return result;
+        }
+
+        int length = 1;
+        int nCodePoints = countCodePoints(input);
+        for(int x=1; x<nCodePoints; x++)
+            length = length * (x+1);
+
+        String[] temp = new String[length];
+
+        int combClass[] = new int[nCodePoints];
+        for(int x=0, i=0; x<nCodePoints; x++) {
+            int c = Character.codePointAt(input, i);
+            combClass[x] = getClass(c);
+            i +=  Character.charCount(c);
+        }
+
+        // For each char, take it out and add the permutations
+        // of the remaining chars
+        int index = 0;
+        int len;
+        // offset maintains the index in code units.
+loop:   for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
+            len = countChars(input, offset, 1);
+            for(int y=x-1; y>=0; y--) {
+                if (combClass[y] == combClass[x]) {
+                    continue loop;
+                }
+            }
+            StringBuilder sb = new StringBuilder(input);
+            String otherChars = sb.delete(offset, offset+len).toString();
+            String[] subResult = producePermutations(otherChars);
+
+            String prefix = input.substring(offset, offset+len);
+            for (String sre : subResult)
+                temp[index++] = prefix + sre;
+        }
+        String[] result = new String[index];
+        System.arraycopy(temp, 0, result, 0, index);
+        return result;
+    }
+
+    private static int getClass(int c) {
+        return sun.text.Normalizer.getCombiningClass(c);
+    }
+
+    /**
+     * Attempts to compose input by combining the first character
+     * with the first combining mark following it. Returns a String
+     * that is the composition of the leading character with its first
+     * combining mark followed by the remaining combining marks. Returns
+     * null if the first two characters cannot be further composed.
+     *
+    private static String composeOneStep(String input) {
+        int len = countChars(input, 0, 2);
+        String firstTwoCharacters = input.substring(0, len);
+        String result = Normalizer.normalize(firstTwoCharacters, Normalizer.Form.NFC);
+        if (result.equals(firstTwoCharacters))
+            return null;
+        else {
+            String remainder = input.substring(len);
+            return result + remainder;
+        }
+    }
+
+    /**
+     * Preprocess any \Q...\E sequences in `temp', meta-quoting them.
+     * See the description of `quotemeta' in perlfunc(1).
+     *
+    private void RemoveQEQuoting() {
+        final int pLen = patternLength;
+        int i = 0;
+        while (i < pLen-1) {
+            if (temp[i] != '\\')
+                i += 1;
+            else if (temp[i + 1] != 'Q')
+                i += 2;
+            else
+                break;
+        }
+        if (i >= pLen - 1)    // No \Q sequence found
+            return;
+        int j = i;
+        i += 2;
+        int newTempLen;
+        try {
+            newTempLen = Math.addExact(j + 2, Math.multiplyExact(3, pLen - i));
+        } catch (ArithmeticException ae) {
+            throw new OutOfMemoryError("Required pattern length too large");
+        }
+        int[] newtemp = new int[newTempLen];
+        System.arraycopy(temp, 0, newtemp, 0, j);
+
+        boolean inQuote = true;
+        boolean beginQuote = true;
+        while (i < pLen) {
+            int c = temp[i++];
+            if (!ASCII.isAscii(c) || ASCII.isAlpha(c)) {
+                newtemp[j++] = c;
+            } else if (ASCII.isDigit(c)) {
+                if (beginQuote) {
+                    /*
+                     * A unicode escape \[0xu] could be before this quote,
+                     * and we don't want this numeric char to processed as
+                     * part of the escape.
+                     *
+                    newtemp[j++] = '\\';
+                    newtemp[j++] = 'x';
+                    newtemp[j++] = '3';
+                }
+                newtemp[j++] = c;
+            } else if (c != '\\') {
+                if (inQuote) newtemp[j++] = '\\';
+                newtemp[j++] = c;
+            } else if (inQuote) {
+                if (temp[i] == 'E') {
+                    i++;
+                    inQuote = false;
+                } else {
+                    newtemp[j++] = '\\';
+                    newtemp[j++] = '\\';
+                }
+            } else {
+                if (temp[i] == 'Q') {
+                    i++;
+                    inQuote = true;
+                    beginQuote = true;
+                    continue;
+                } else {
+                    newtemp[j++] = c;
+                    if (i != pLen)
+                        newtemp[j++] = temp[i++];
+                }
+            }
+
+            beginQuote = false;
+        }
+
+        patternLength = j;
+        temp = Arrays.copyOf(newtemp, j + 2); // double zero termination
+    }
+
+    /**
+     * Copies regular expression to an int array and invokes the parsing
+     * of the expression which will create the object tree.
+     *
+    private void compile() {
+        // Handle canonical equivalences
+        if (has(CANON_EQ) && !has(LITERAL)) {
+            normalizedPattern = normalize(pattern);
+        } else {
+            normalizedPattern = pattern;
+        }
+        patternLength = normalizedPattern.length();
+
+        // Copy pattern to int array for convenience
+        // Use double zero to terminate pattern
+        temp = new int[patternLength + 2];
+
+        hasSupplementary = false;
+        int c, count = 0;
+        // Convert all chars into code points
+        for (int x = 0; x < patternLength; x += Character.charCount(c)) {
+            c = normalizedPattern.codePointAt(x);
+            if (isSupplementary(c)) {
+                hasSupplementary = true;
+            }
+            temp[count++] = c;
+        }
+
+        patternLength = count;   // patternLength now in code points
+
+        if (! has(LITERAL))
+            RemoveQEQuoting();
+
+        // Allocate all temporary objects here.
+        buffer = new int[32];
+        groupNodes = new GroupHead[10];
+        namedGroups = null;
+        topClosureNodes = new ArrayList<>(10);
+
+        if (has(LITERAL)) {
+            // Literal pattern handling
+            matchRoot = newSlice(temp, patternLength, hasSupplementary);
+            matchRoot.next = lastAccept;
+        } else {
+            // Start recursive descent parsing
+            matchRoot = expr(lastAccept);
+            // Check extra pattern characters
+            if (patternLength != cursor) {
+                if (peek() == ')') {
+                    throw error("Unmatched closing ')'");
+                } else {
+                    throw error("Unexpected internal error");
+                }
+            }
+        }
+
+        // Peephole optimization
+        if (matchRoot instanceof Slice) {
+            root = BnM.optimize(matchRoot);
+            if (root == matchRoot) {
+                root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
+            }
+        } else if (matchRoot instanceof Begin || matchRoot instanceof First) {
+            root = matchRoot;
+        } else {
+            root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
+        }
+
+        // Optimize the greedy Loop to prevent exponential backtracking, IF there
+        // is no group ref in this pattern. With a non-negative localTCNCount value,
+        // the greedy type Loop, Curly will skip the backtracking for any starting
+        // position "i" that failed in the past.
+        if (!hasGroupRef) {
+            for (Node node : topClosureNodes) {
+                if (node instanceof Loop) {
+                    // non-deterministic-greedy-group
+                    ((Loop)node).posIndex = localTCNCount++;
+                }
+            }
+        }
+
+        // Release temporary storage
+        temp = null;
+        buffer = null;
+        groupNodes = null;
+        patternLength = 0;
+        compiled = true;
+        topClosureNodes = null;
+    }
+
+    Map<String, Integer> namedGroups() {
+        Map<String, Integer> groups = namedGroups;
+        if (groups == null) {
+            namedGroups = groups = new HashMap<>(2);
+        }
+        return groups;
+    }
+
+    /**
+     * Used to accumulate information about a subtree of the object graph
+     * so that optimizations can be applied to the subtree.
+     *
+    static final class TreeInfo {
+        int minLength;
+        int maxLength;
+        boolean maxValid;
+        boolean deterministic;
+
+        TreeInfo() {
+            reset();
+        }
+        void reset() {
+            minLength = 0;
+            maxLength = 0;
+            maxValid = true;
+            deterministic = true;
+        }
+    }
+
+    /*
+     * The following private methods are mainly used to improve the
+     * readability of the code. In order to let the Java compiler easily
+     * inline them, we should not put many assertions or error checks in them.
+     *
+
+    /**
+     * Indicates whether a particular flag is set or not.
+     *
+    private boolean has(int f) {
+        return (flags0 & f) != 0;
+    }
+
+    /**
+     * Match next character, signal error if failed.
+     *
+    private void accept(int ch, String s) {
+        int testChar = temp[cursor++];
+        if (has(COMMENTS))
+            testChar = parsePastWhitespace(testChar);
+        if (ch != testChar) {
+            throw error(s);
+        }
+    }
+
+    /**
+     * Mark the end of pattern with a specific character.
+     *
+    private void mark(int c) {
+        temp[patternLength] = c;
+    }
+
+    /**
+     * Peek the next character, and do not advance the cursor.
+     *
+    private int peek() {
+        int ch = temp[cursor];
+        if (has(COMMENTS))
+            ch = peekPastWhitespace(ch);
+        return ch;
+    }
+
+    /**
+     * Read the next character, and advance the cursor by one.
+     *
+    private int read() {
+        int ch = temp[cursor++];
+        if (has(COMMENTS))
+            ch = parsePastWhitespace(ch);
+        return ch;
+    }
+
+    /**
+     * Read the next character, and advance the cursor by one,
+     * ignoring the COMMENTS setting
+     *
+    private int readEscaped() {
+        int ch = temp[cursor++];
+        return ch;
+    }
+
+    /**
+     * Advance the cursor by one, and peek the next character.
+     *
+    private int next() {
+        int ch = temp[++cursor];
+        if (has(COMMENTS))
+            ch = peekPastWhitespace(ch);
+        return ch;
+    }
+
+    /**
+     * Advance the cursor by one, and peek the next character,
+     * ignoring the COMMENTS setting
+     *
+    private int nextEscaped() {
+        int ch = temp[++cursor];
+        return ch;
+    }
+
+    /**
+     * If in xmode peek past whitespace and comments.
+     *
+    private int peekPastWhitespace(int ch) {
+        while (ASCII.isSpace(ch) || ch == '#') {
+            while (ASCII.isSpace(ch))
+                ch = temp[++cursor];
+            if (ch == '#') {
+                ch = peekPastLine();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * If in xmode parse past whitespace and comments.
+     *
+    private int parsePastWhitespace(int ch) {
+        while (ASCII.isSpace(ch) || ch == '#') {
+            while (ASCII.isSpace(ch))
+                ch = temp[cursor++];
+            if (ch == '#')
+                ch = parsePastLine();
+        }
+        return ch;
+    }
+
+    /**
+     * xmode parse past comment to end of line.
+     *
+    private int parsePastLine() {
+        int ch = temp[cursor++];
+        while (ch != 0 && !isLineSeparator(ch))
+            ch = temp[cursor++];
+        if (ch == 0 && cursor > patternLength) {
+            cursor = patternLength;
+            ch = temp[cursor++];
+        }
+        return ch;
+    }
+
+    /**
+     * xmode peek past comment to end of line.
+     *
+    private int peekPastLine() {
+        int ch = temp[++cursor];
+        while (ch != 0 && !isLineSeparator(ch))
+            ch = temp[++cursor];
+        if (ch == 0 && cursor > patternLength) {
+            cursor = patternLength;
+            ch = temp[cursor];
+        }
+        return ch;
+    }
+
+    /**
+     * Determines if character is a line separator in the current mode
+     *
+    private boolean isLineSeparator(int ch) {
+        if (has(UNIX_LINES)) {
+            return ch == '\n';
+        } else {
+            return (ch == '\n' ||
+                    ch == '\r' ||
+                    (ch|1) == '\u2029' ||
+                    ch == '\u0085');
+        }
+    }
+
+    /**
+     * Read the character after the next one, and advance the cursor by two.
+     *
+    private int skip() {
+        int i = cursor;
+        int ch = temp[i+1];
+        cursor = i + 2;
+        return ch;
+    }
+
+    /**
+     * Unread one next character, and retreat cursor by one.
+     *
+    private void unread() {
+        cursor--;
+    }
+
+    /**
+     * Internal method used for handling all syntax errors. The pattern is
+     * displayed with a pointer to aid in locating the syntax error.
+     *
+    private PatternSyntaxException error(String s) {
+        return new PatternSyntaxException(s, normalizedPattern,  cursor - 1);
+    }
+
+    /**
+     * Determines if there is any supplementary character or unpaired
+     * surrogate in the specified range.
+     *
+    private boolean findSupplementary(int start, int end) {
+        for (int i = start; i < end; i++) {
+            if (isSupplementary(temp[i]))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Determines if the specified code point is a supplementary
+     * character or unpaired surrogate.
+     *
+    private static final boolean isSupplementary(int ch) {
+        return ch >= Character.MIN_SUPPLEMENTARY_CODE_POINT ||
+               Character.isSurrogate((char)ch);
+    }
+
+    /**
+     *  The following methods handle the main parsing. They are sorted
+     *  according to their precedence order, the lowest one first.
+     *
+
+    /**
+     * The expression is parsed with branch nodes added for alternations.
+     * This may be called recursively to parse sub expressions that may
+     * contain alternations.
+     *
+    private Node expr(Node end) {
+        Node prev = null;
+        Node firstTail = null;
+        Branch branch = null;
+        Node branchConn = null;
+
+        for (;;) {
+            Node node = sequence(end);
+            Node nodeTail = root;      //double return
+            if (prev == null) {
+                prev = node;
+                firstTail = nodeTail;
+            } else {
+                // Branch
+                if (branchConn == null) {
+                    branchConn = new BranchConn();
+                    branchConn.next = end;
+                }
+                if (node == end) {
+                    // if the node returned from sequence() is "end"
+                    // we have an empty expr, set a null atom into
+                    // the branch to indicate to go "next" directly.
+                    node = null;
+                } else {
+                    // the "tail.next" of each atom goes to branchConn
+                    nodeTail.next = branchConn;
+                }
+                if (prev == branch) {
+                    branch.add(node);
+                } else {
+                    if (prev == end) {
+                        prev = null;
+                    } else {
+                        // replace the "end" with "branchConn" at its tail.next
+                        // when put the "prev" into the branch as the first atom.
+                        firstTail.next = branchConn;
+                    }
+                    prev = branch = new Branch(prev, node, branchConn);
+                }
+            }
+            if (peek() != '|') {
+                return prev;
+            }
+            next();
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    /**
+     * Parsing of sequences between alternations.
+     *
+    private Node sequence(Node end) {
+        Node head = null;
+        Node tail = null;
+        Node node;
+    LOOP:
+        for (;;) {
+            int ch = peek();
+            switch (ch) {
+            case '(':
+                // Because group handles its own closure,
+                // we need to treat it differently
+                node = group0();
+                // Check for comment or flag group
+                if (node == null)
+                    continue;
+                if (head == null)
+                    head = node;
+                else
+                    tail.next = node;
+                // Double return: Tail was returned in root
+                tail = root;
+                continue;
+            case '[':
+                if (has(CANON_EQ) && !has(LITERAL))
+                    node = new NFCCharProperty(clazz(true));
+                else
+                    node = newCharProperty(clazz(true));
+                break;
+            case '\\':
+                ch = nextEscaped();
+                if (ch == 'p' || ch == 'P') {
+                    boolean oneLetter = true;
+                    boolean comp = (ch == 'P');
+                    ch = next(); // Consume { if present
+                    if (ch != '{') {
+                        unread();
+                    } else {
+                        oneLetter = false;
+                    }
+                    // node = newCharProperty(family(oneLetter, comp));
+                    if (has(CANON_EQ) && !has(LITERAL))
+                        node = new NFCCharProperty(family(oneLetter, comp));
+                    else
+                        node = newCharProperty(family(oneLetter, comp));
+                } else {
+                    unread();
+                    node = atom();
+                }
+                break;
+            case '^':
+                next();
+                if (has(MULTILINE)) {
+                    if (has(UNIX_LINES))
+                        node = new UnixCaret();
+                    else
+                        node = new Caret();
+                } else {
+                    node = new Begin();
+                }
+                break;
+            case '$':
+                next();
+                if (has(UNIX_LINES))
+                    node = new UnixDollar(has(MULTILINE));
+                else
+                    node = new Dollar(has(MULTILINE));
+                break;
+            case '.':
+                next();
+                if (has(DOTALL)) {
+                    node = new CharProperty(ALL());
+                } else {
+                    if (has(UNIX_LINES)) {
+                        node = new CharProperty(UNIXDOT());
+                    } else {
+                        node = new CharProperty(DOT());
+                    }
+                }
+                break;
+            case '|':
+            case ')':
+                break LOOP;
+            case ']': // Now interpreting dangling ] and } as literals
+            case '}':
+                node = atom();
+                break;
+            case '?':
+            case '*':
+            case '+':
+                next();
+                throw error("Dangling meta character '" + ((char)ch) + "'");
+            case 0:
+                if (cursor >= patternLength) {
+                    break LOOP;
+                }
+                // Fall through
+            default:
+                node = atom();
+                break;
+            }
+
+            node = closure(node);
+            /* save the top dot-greedy nodes (.*, .+) as well
+            if (node instanceof GreedyCharProperty &&
+                ((GreedyCharProperty)node).cp instanceof Dot) {
+                topClosureNodes.add(node);
+            }
+            *
+            if (head == null) {
+                head = tail = node;
+            } else {
+                tail.next = node;
+                tail = node;
+            }
+        }
+        if (head == null) {
+            return end;
+        }
+        tail.next = end;
+        root = tail;      //double return
+        return head;
+    }
+
+    @SuppressWarnings("fallthrough")
+    /**
+     * Parse and add a new Single or Slice.
+     *
+    private Node atom() {
+        int first = 0;
+        int prev = -1;
+        boolean hasSupplementary = false;
+        int ch = peek();
+        for (;;) {
+            switch (ch) {
+            case '*':
+            case '+':
+            case '?':
+            case '{':
+                if (first > 1) {
+                    cursor = prev;    // Unwind one character
+                    first--;
+                }
+                break;
+            case '$':
+            case '.':
+            case '^':
+            case '(':
+            case '[':
+            case '|':
+            case ')':
+                break;
+            case '\\':
+                ch = nextEscaped();
+                if (ch == 'p' || ch == 'P') { // Property
+                    if (first > 0) { // Slice is waiting; handle it first
+                        unread();
+                        break;
+                    } else { // No slice; just return the family node
+                        boolean comp = (ch == 'P');
+                        boolean oneLetter = true;
+                        ch = next(); // Consume { if present
+                        if (ch != '{')
+                            unread();
+                        else
+                            oneLetter = false;
+                        if (has(CANON_EQ) && !has(LITERAL))
+                            return new NFCCharProperty(family(oneLetter, comp));
+                        else
+                            return newCharProperty(family(oneLetter, comp));
+                    }
+                }
+                unread();
+                prev = cursor;
+                ch = escape(false, first == 0, false);
+                if (ch >= 0) {
+                    append(ch, first);
+                    first++;
+                    if (isSupplementary(ch)) {
+                        hasSupplementary = true;
+                    }
+                    ch = peek();
+                    continue;
+                } else if (first == 0) {
+                    return root;
+                }
+                // Unwind meta escape sequence
+                cursor = prev;
+                break;
+            case 0:
+                if (cursor >= patternLength) {
+                    break;
+                }
+                // Fall through
+            default:
+                prev = cursor;
+                append(ch, first);
+                first++;
+                if (isSupplementary(ch)) {
+                    hasSupplementary = true;
+                }
+                ch = next();
+                continue;
+            }
+            break;
+        }
+        if (first == 1) {
+            return newCharProperty(single(buffer[0]));
+        } else {
+            return newSlice(buffer, first, hasSupplementary);
+        }
+    }
+
+    private void append(int ch, int index) {
+        int len = buffer.length;
+        if (index - len >= 0) {
+            len = ArraysSupport.newLength(len,
+                    1 + index - len, /* minimum growth * /
+                    len              /* preferred growth * /);
+            buffer = Arrays.copyOf(buffer, len);
+        }
+        buffer[index] = ch;
+    }
+
+    /**
+     * Parses a backref greedily, taking as many numbers as it
+     * can. The first digit is always treated as a backref, but
+     * multi digit numbers are only treated as a backref if at
+     * least that many backrefs exist at this point in the regex.
+     *
+    private Node ref(int refNum) {
+        boolean done = false;
+        while(!done) {
+            int ch = peek();
+            switch (ch) {
+                case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> {
+                    int newRefNum = (refNum * 10) + (ch - '0');
+                    // Add another number if it doesn't make a group
+                    // that doesn't exist
+                    if (capturingGroupCount - 1 < newRefNum) {
+                        done = true;
+                        break;
+                    }
+                    refNum = newRefNum;
+                    read();
+                }
+                default -> done = true;
+            }
+        }
+        hasGroupRef = true;
+        if (has(CASE_INSENSITIVE))
+            return new CIBackRef(refNum, has(UNICODE_CASE));
+        else
+            return new BackRef(refNum);
+    }
+
+    /**
+     * Parses an escape sequence to determine the actual value that needs
+     * to be matched.
+     * If -1 is returned and create was true a new object was added to the tree
+     * to handle the escape sequence.
+     * If the returned value is greater than zero, it is the value that
+     * matches the escape sequence.
+     *
+    private int escape(boolean inclass, boolean create, boolean isrange) {
+        int ch = skip();
+        switch (ch) {
+        case '0':
+            return o();
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            if (inclass) break;
+            if (create) {
+                root = ref((ch - '0'));
+            }
+            return -1;
+        case 'A':
+            if (inclass) break;
+            if (create) root = new Begin();
+            return -1;
+        case 'B':
+            if (inclass) break;
+            if (create) root = new Bound(Bound.NONE, has(UNICODE_CHARACTER_CLASS));
+            return -1;
+        case 'C':
+            break;
+        case 'D':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.DIGIT() : CharPredicates.ASCII_DIGIT();
+                predicate = predicate.negate();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'E':
+        case 'F':
+            break;
+        case 'G':
+            if (inclass) break;
+            if (create) root = new LastMatch();
+            return -1;
+        case 'H':
+            if (create) {
+                predicate = HorizWS().negate();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'I':
+        case 'J':
+        case 'K':
+        case 'L':
+        case 'M':
+            break;
+        case 'N':
+            return N();
+        case 'O':
+        case 'P':
+        case 'Q':
+            break;
+        case 'R':
+            if (inclass) break;
+            if (create) root = new LineEnding();
+            return -1;
+        case 'S':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.WHITE_SPACE() : CharPredicates.ASCII_SPACE();
+                predicate = predicate.negate();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'T':
+        case 'U':
+            break;
+        case 'V':
+            if (create) {
+                predicate = VertWS().negate();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'W':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.WORD() : CharPredicates.ASCII_WORD();
+                predicate = predicate.negate();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'X':
+            if (inclass) break;
+            if (create) {
+                root = new XGrapheme();
+            }
+            return -1;
+        case 'Y':
+            break;
+        case 'Z':
+            if (inclass) break;
+            if (create) {
+                if (has(UNIX_LINES))
+                    root = new UnixDollar(false);
+                else
+                    root = new Dollar(false);
+            }
+            return -1;
+        case 'a':
+            return '\007';
+        case 'b':
+            if (inclass) break;
+            if (create) {
+                if (peek() == '{') {
+                    if (skip() == 'g') {
+                        if (read() == '}') {
+                            root = new GraphemeBound();
+                            return -1;
+                        }
+                        break;  // error missing trailing }
+                    }
+                    unread(); unread();
+                }
+                root = new Bound(Bound.BOTH, has(UNICODE_CHARACTER_CLASS));
+            }
+            return -1;
+        case 'c':
+            return c();
+        case 'd':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.DIGIT() : CharPredicates.ASCII_DIGIT();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'e':
+            return '\033';
+        case 'f':
+            return '\f';
+        case 'g':
+            break;
+        case 'h':
+            if (create) {
+                predicate = HorizWS();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'i':
+        case 'j':
+            break;
+        case 'k':
+            if (inclass)
+                break;
+            if (read() != '<')
+                throw error("\\k is not followed by '<' for named capturing group");
+            String name = groupname(read());
+            if (!namedGroups().containsKey(name))
+                throw error("named capturing group <" + name + "> does not exist");
+            if (create) {
+                hasGroupRef = true;
+                if (has(CASE_INSENSITIVE))
+                    root = new CIBackRef(namedGroups().get(name), has(UNICODE_CASE));
+                else
+                    root = new BackRef(namedGroups().get(name));
+            }
+            return -1;
+        case 'l':
+        case 'm':
+            break;
+        case 'n':
+            return '\n';
+        case 'o':
+        case 'p':
+        case 'q':
+            break;
+        case 'r':
+            return '\r';
+        case 's':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.WHITE_SPACE() : CharPredicates.ASCII_SPACE();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 't':
+            return '\t';
+        case 'u':
+            return u();
+        case 'v':
+            // '\v' was implemented as VT/0x0B in releases < 1.8 (though
+            // undocumented). In JDK8 '\v' is specified as a predefined
+            // character class for all vertical whitespace characters.
+            // So [-1, root=VertWS node] pair is returned (instead of a
+            // single 0x0B). This breaks the range if '\v' is used as
+            // the start or end value, such as [\v-...] or [...-\v], in
+            // which a single definite value (0x0B) is expected. For
+            // compatibility concern '\013'/0x0B is returned if isrange.
+            if (isrange)
+                return '\013';
+            if (create) {
+                predicate = VertWS();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'w':
+            if (create) {
+                predicate = has(UNICODE_CHARACTER_CLASS) ?
+                            CharPredicates.WORD() : CharPredicates.ASCII_WORD();
+                if (!inclass)
+                    root = newCharProperty(predicate);
+            }
+            return -1;
+        case 'x':
+            return x();
+        case 'y':
+            break;
+        case 'z':
+            if (inclass) break;
+            if (create) root = new End();
+            return -1;
+        default:
+            return ch;
+        }
+        throw error("Illegal/unsupported escape sequence");
+    }
+
+    /**
+     * Parse a character class, and return the node that matches it.
+     *
+     * Consumes a ] on the way out if consume is true. Usually consume
+     * is true except for the case of [abc&&def] where def is a separate
+     * right hand node with "understood" brackets.
+     *
+    private CharPredicate clazz(boolean consume) {
+        CharPredicate prev = null;
+        CharPredicate curr = null;
+        BitClass bits = new BitClass();
+
+        boolean isNeg = false;
+        boolean hasBits = false;
+        int ch = next();
+
+        // Negates if first char in a class, otherwise literal
+        if (ch == '^' && temp[cursor-1] == '[') {
+            ch = next();
+            isNeg = true;
+        }
+        for (;;) {
+            switch (ch) {
+                case '[':
+                    curr = clazz(true);
+                    if (prev == null)
+                        prev = curr;
+                    else
+                        prev = prev.union(curr);
+                    ch = peek();
+                    continue;
+                case '&':
+                    ch = next();
+                    if (ch == '&') {
+                        ch = next();
+                        CharPredicate right = null;
+                        while (ch != ']' && ch != '&') {
+                            if (ch == '[') {
+                                if (right == null)
+                                    right = clazz(true);
+                                else
+                                    right = right.union(clazz(true));
+                            } else { // abc&&def
+                                unread();
+                                if (right == null) {
+                                    right = clazz(false);
+                                } else {
+                                    right = right.union(clazz(false));
+                                }
+                            }
+                            ch = peek();
+                        }
+                        if (hasBits) {
+                            // bits used, union has high precedence
+                            if (prev == null) {
+                                prev = curr = bits;
+                            } else {
+                                prev = prev.union(bits);
+                            }
+                            hasBits = false;
+                        }
+                        if (right != null)
+                            curr = right;
+                        if (prev == null) {
+                            if (right == null)
+                                throw error("Bad class syntax");
+                            else
+                                prev = right;
+                        } else {
+                            prev = prev.and(curr);
+                        }
+                    } else {
+                        // treat as a literal &
+                        unread();
+                        break;
+                    }
+                    continue;
+                case 0:
+                    if (cursor >= patternLength)
+                        throw error("Unclosed character class");
+                    break;
+                case ']':
+                    if (prev != null || hasBits) {
+                        if (consume)
+                            next();
+                        if (prev == null)
+                            prev = bits;
+                        else if (hasBits)
+                            prev = prev.union(bits);
+                        if (isNeg)
+                            return prev.negate();
+                        return prev;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            curr = range(bits);
+            if (curr == null) {    // the bits used
+                hasBits = true;
+            } else {
+                if (prev == null)
+                    prev = curr;
+                else if (prev != curr)
+                    prev = prev.union(curr);
+            }
+            ch = peek();
+        }
+    }
+
+    private CharPredicate bitsOrSingle(BitClass bits, int ch) {
+        /* Bits can only handle codepoints in [u+0000-u+00ff] range.
+           Use "single" node instead of bits when dealing with unicode
+           case folding for codepoints listed below.
+           (1)Uppercase out of range: u+00ff, u+00b5
+              toUpperCase(u+00ff) -> u+0178
+              toUpperCase(u+00b5) -> u+039c
+           (2)LatinSmallLetterLongS u+17f
+              toUpperCase(u+017f) -> u+0053
+           (3)LatinSmallLetterDotlessI u+131
+              toUpperCase(u+0131) -> u+0049
+           (4)LatinCapitalLetterIWithDotAbove u+0130
+              toLowerCase(u+0130) -> u+0069
+           (5)KelvinSign u+212a
+              toLowerCase(u+212a) ==> u+006B
+           (6)AngstromSign u+212b
+              toLowerCase(u+212b) ==> u+00e5
+        *
+        if (ch < 256 &&
+            !(has(CASE_INSENSITIVE) && has(UNICODE_CASE) &&
+              (ch == 0xff || ch == 0xb5 ||
+               ch == 0x49 || ch == 0x69 ||    //I and i
+               ch == 0x53 || ch == 0x73 ||    //S and s
+               ch == 0x4b || ch == 0x6b ||    //K and k
+               ch == 0xc5 || ch == 0xe5))) {  //A+ring
+            bits.add(ch, flags0);
+            return null;
+        }
+        return single(ch);
+    }
+
+    /**
+     *  Returns a suitably optimized, single character predicate
+     *
+    private CharPredicate single(final int ch) {
+        if (has(CASE_INSENSITIVE)) {
+            int lower, upper;
+            if (has(UNICODE_CASE)) {
+                upper = Character.toUpperCase(ch);
+                lower = Character.toLowerCase(upper);
+                // Unicode case insensitive matches
+                if (upper != lower)
+                    return SingleU(lower);
+            } else if (ASCII.isAscii(ch)) {
+                lower = ASCII.toLower(ch);
+                upper = ASCII.toUpper(ch);
+                // Case insensitive matches a given BMP character
+                if (lower != upper)
+                    return SingleI(lower, upper);
+            }
+        }
+        if (isSupplementary(ch))
+            return SingleS(ch);
+        return Single(ch);  // Match a given BMP character
+    }
+
+    /**
+     * Parse a single character or a character range in a character class
+     * and return its representative node.
+     *
+    private CharPredicate range(BitClass bits) {
+        int ch = peek();
+        if (ch == '\\') {
+            ch = nextEscaped();
+            if (ch == 'p' || ch == 'P') { // A property
+                boolean comp = (ch == 'P');
+                boolean oneLetter = true;
+                // Consume { if present
+                ch = next();
+                if (ch != '{')
+                    unread();
+                else
+                    oneLetter = false;
+                return family(oneLetter, comp);
+            } else { // ordinary escape
+                boolean isrange = temp[cursor+1] == '-';
+                unread();
+                ch = escape(true, true, isrange);
+                if (ch == -1)
+                    return predicate;
+            }
+        } else {
+            next();
+        }
+        if (ch >= 0) {
+            if (peek() == '-') {
+                int endRange = temp[cursor+1];
+                if (endRange == '[') {
+                    return bitsOrSingle(bits, ch);
+                }
+                if (endRange != ']') {
+                    next();
+                    int m = peek();
+                    if (m == '\\') {
+                        m = escape(true, false, true);
+                    } else {
+                        next();
+                    }
+                    if (m < ch) {
+                        throw error("Illegal character range");
+                    }
+                    if (has(CASE_INSENSITIVE)) {
+                        if (has(UNICODE_CASE))
+                            return CIRangeU(ch, m);
+                        return CIRange(ch, m);
+                    } else {
+                        return Range(ch, m);
+                    }
+                }
+            }
+            return bitsOrSingle(bits, ch);
+        }
+        throw error("Unexpected character '"+((char)ch)+"'");
+    }
+
+    /**
+     * Parses a Unicode character family and returns its representative node.
+     *
+    private CharPredicate family(boolean singleLetter, boolean isComplement) {
+        next();
+        String name;
+        CharPredicate p = null;
+
+        if (singleLetter) {
+            int c = temp[cursor];
+            if (!Character.isSupplementaryCodePoint(c)) {
+                name = String.valueOf((char)c);
+            } else {
+                name = new String(temp, cursor, 1);
+            }
+            read();
+        } else {
+            int i = cursor;
+            mark('}');
+            while(read() != '}') {
+            }
+            mark('\000');
+            int j = cursor;
+            if (j > patternLength)
+                throw error("Unclosed character family");
+            if (i + 1 >= j)
+                throw error("Empty character family");
+            name = new String(temp, i, j-i-1);
+        }
+
+        int i = name.indexOf('=');
+        if (i != -1) {
+            // property construct \p{name=value}
+            String value = name.substring(i + 1);
+            name = name.substring(0, i).toLowerCase(Locale.ENGLISH);
+            switch (name) {
+                case "sc":
+                case "script":
+                    p = CharPredicates.forUnicodeScript(value);
+                    break;
+                case "blk":
+                case "block":
+                    p = CharPredicates.forUnicodeBlock(value);
+                    break;
+                case "gc":
+                case "general_category":
+                    p = CharPredicates.forProperty(value, has(CASE_INSENSITIVE));
+                    break;
+                default:
+                    break;
+            }
+            if (p == null)
+                throw error("Unknown Unicode property {name=<" + name + ">, "
+                             + "value=<" + value + ">}");
+
+        } else {
+            if (name.startsWith("In")) {
+                // \p{InBlockName}
+                p = CharPredicates.forUnicodeBlock(name.substring(2));
+            } else if (name.startsWith("Is")) {
+                // \p{IsGeneralCategory} and \p{IsScriptName}
+                String shortName = name.substring(2);
+                p = CharPredicates.forUnicodeProperty(shortName, has(CASE_INSENSITIVE));
+                if (p == null)
+                    p = CharPredicates.forProperty(shortName, has(CASE_INSENSITIVE));
+                if (p == null)
+                    p = CharPredicates.forUnicodeScript(shortName);
+            } else {
+                if (has(UNICODE_CHARACTER_CLASS))
+                    p = CharPredicates.forPOSIXName(name, has(CASE_INSENSITIVE));
+                if (p == null)
+                    p = CharPredicates.forProperty(name, has(CASE_INSENSITIVE));
+            }
+            if (p == null)
+                throw error("Unknown character property name {" + name + "}");
+        }
+        if (isComplement) {
+            // it might be too expensive to detect if a complement of
+            // CharProperty can match "certain" supplementary. So just
+            // go with StartS.
+            hasSupplementary = true;
+            p = p.negate();
+        }
+        return p;
+    }
+
+    private CharProperty newCharProperty(CharPredicate p) {
+        if (p == null)
+            return null;
+        if (p instanceof BmpCharPredicate)
+            return new BmpCharProperty((BmpCharPredicate)p);
+        else {
+            hasSupplementary = true;
+            return new CharProperty(p);
+        }
+    }
+
+    /**
+     * Parses and returns the name of a "named capturing group", the trailing
+     * ">" is consumed after parsing.
+     *
+    private String groupname(int ch) {
+        StringBuilder sb = new StringBuilder();
+        if (!ASCII.isAlpha(ch))
+            throw error("capturing group name does not start with a Latin letter");
+        do {
+            sb.append((char) ch);
+        } while (ASCII.isAlnum(ch=read()));
+        if (ch != '>')
+            throw error("named capturing group is missing trailing '>'");
+        return sb.toString();
+    }
+
+    /**
+     * Parses a group and returns the head node of a set of nodes that process
+     * the group. Sometimes a double return system is used where the tail is
+     * returned in root.
+     *
+    private Node group0() {
+        boolean capturingGroup = false;
+        Node head;
+        Node tail;
+        int save = flags0;
+        int saveTCNCount = topClosureNodes.size();
+        root = null;
+        int ch = next();
+        if (ch == '?') {
+            ch = skip();
+            switch (ch) {
+                case ':' -> {   //  (?:xxx) pure group
+                    head = createGroup(true);
+                    tail = root;
+                    head.next = expr(tail);
+                }
+                case '=', '!' -> {   // (?=xxx) and (?!xxx) lookahead
+                    head = createGroup(true);
+                    tail = root;
+                    head.next = expr(tail);
+                    if (ch == '=') {
+                        head = tail = new Pos(head);
+                    } else {
+                        head = tail = new Neg(head);
+                    }
+                }
+                case '>' -> {   // (?>xxx)  independent group
+                    head = createGroup(true);
+                    tail = root;
+                    head.next = expr(tail);
+                    head = tail = new Ques(head, Qtype.INDEPENDENT);
+                }
+                case '<' -> {   // (?<xxx)  look behind
+                    ch = read();
+                    if (ch != '=' && ch != '!') {
+                        // named captured group
+                        String name = groupname(ch);
+                        if (namedGroups().containsKey(name))
+                            throw error("Named capturing group <" + name
+                                        + "> is already defined");
+                        capturingGroup = true;
+                        head = createGroup(false);
+                        tail = root;
+                        namedGroups().put(name, capturingGroupCount - 1);
+                        head.next = expr(tail);
+                        break;
+                    }
+                    int start = cursor;
+                    head = createGroup(true);
+                    tail = root;
+                    head.next = expr(tail);
+                    tail.next = LookBehindEndNode.INSTANCE;
+                    TreeInfo info = new TreeInfo();
+                    head.study(info);
+                    if (info.maxValid == false) {
+                        throw error("Look-behind group does not have "
+                                    + "an obvious maximum length");
+                    }
+                    boolean hasSupplementary = findSupplementary(start, patternLength);
+                    if (ch == '=') {
+                        head = tail = (hasSupplementary ?
+                            new BehindS(head, info.maxLength,
+                                info.minLength) :
+                            new Behind(head, info.maxLength,
+                                info.minLength));
+                    } else { // if (ch == '!')
+                        head = tail = (hasSupplementary ?
+                            new NotBehindS(head, info.maxLength,
+                                info.minLength) :
+                            new NotBehind(head, info.maxLength,
+                                info.minLength));
+                    }
+                    // clear all top-closure-nodes inside lookbehind
+                    if (saveTCNCount < topClosureNodes.size())
+                        topClosureNodes.subList(saveTCNCount, topClosureNodes.size()).clear();
+                }
+                case '$', '@' -> throw error("Unknown group type");
+                default -> {    // (?xxx:) inlined match flags
+                    unread();
+                    addFlag();
+                    ch = read();
+                    if (ch == ')') {
+                        return null;    // Inline modifier only
+                    }
+                    if (ch != ':') {
+                        throw error("Unknown inline modifier");
+                    }
+                    head = createGroup(true);
+                    tail = root;
+                    head.next = expr(tail);
+                }
+            }
+        } else { // (xxx) a regular group
+            capturingGroup = true;
+            head = createGroup(false);
+            tail = root;
+            head.next = expr(tail);
+        }
+
+        accept(')', "Unclosed group");
+        flags0 = save;
+
+        // Check for quantifiers
+        Node node = closure(head);
+        if (node == head) { // No closure
+            root = tail;
+            return node;    // Dual return
+        }
+        if (head == tail) { // Zero length assertion
+            root = node;
+            return node;    // Dual return
+        }
+
+        // have group closure, clear all inner closure nodes from the
+        // top list (no backtracking stopper optimization for inner
+        if (saveTCNCount < topClosureNodes.size())
+            topClosureNodes.subList(saveTCNCount, topClosureNodes.size()).clear();
+
+        if (node instanceof Ques ques) {
+            if (ques.type == Qtype.POSSESSIVE) {
+                root = node;
+                return node;
+            }
+            tail.next = new BranchConn();
+            tail = tail.next;
+            if (ques.type == Qtype.GREEDY) {
+                head = new Branch(head, null, tail);
+            } else { // Reluctant quantifier
+                head = new Branch(null, head, tail);
+            }
+            root = tail;
+            return head;
+        } else if (node instanceof Curly curly) {
+            if (curly.type == Qtype.POSSESSIVE) {
+                root = node;
+                return node;
+            }
+            // Discover if the group is deterministic
+            TreeInfo info = new TreeInfo();
+            if (head.study(info)) { // Deterministic
+                GroupTail temp = (GroupTail) tail;
+                head = root = new GroupCurly(head.next, curly.cmin,
+                                   curly.cmax, curly.type,
+                                   ((GroupTail)tail).localIndex,
+                                   ((GroupTail)tail).groupIndex,
+                                             capturingGroup);
+                return head;
+            } else { // Non-deterministic
+                int temp = ((GroupHead) head).localIndex;
+                Loop loop;
+                if (curly.type == Qtype.GREEDY) {
+                    loop = new Loop(this.localCount, temp);
+                    // add the max_reps greedy to the top-closure-node list
+                    if (curly.cmax == MAX_REPS)
+                        topClosureNodes.add(loop);
+                } else {  // Reluctant Curly
+                    loop = new LazyLoop(this.localCount, temp);
+                }
+                Prolog prolog = new Prolog(loop);
+                this.localCount += 1;
+                loop.cmin = curly.cmin;
+                loop.cmax = curly.cmax;
+                loop.body = head;
+                tail.next = loop;
+                root = loop;
+                return prolog; // Dual return
+            }
+        }
+        throw error("Internal logic error");
+    }
+
+    /**
+     * Create group head and tail nodes using double return. If the group is
+     * created with anonymous true then it is a pure group and should not
+     * affect group counting.
+     *
+    private Node createGroup(boolean anonymous) {
+        int localIndex = localCount++;
+        int groupIndex = 0;
+        if (!anonymous)
+            groupIndex = capturingGroupCount++;
+        GroupHead head = new GroupHead(localIndex);
+        root = new GroupTail(localIndex, groupIndex);
+
+        // for debug/print only, head.match does NOT need the "tail" info
+        head.tail = (GroupTail)root;
+
+        if (!anonymous && groupIndex < 10)
+            groupNodes[groupIndex] = head;
+        return head;
+    }
+
+    @SuppressWarnings("fallthrough")
+    /**
+     * Parses inlined match flags and set them appropriately.
+     *
+    private void addFlag() {
+        int ch = peek();
+        for (;;) {
+            switch (ch) {
+            case 'i':
+                flags0 |= CASE_INSENSITIVE;
+                break;
+            case 'm':
+                flags0 |= MULTILINE;
+                break;
+            case 's':
+                flags0 |= DOTALL;
+                break;
+            case 'd':
+                flags0 |= UNIX_LINES;
+                break;
+            case 'u':
+                flags0 |= UNICODE_CASE;
+                break;
+            case 'c':
+                flags0 |= CANON_EQ;
+                break;
+            case 'x':
+                flags0 |= COMMENTS;
+                break;
+            case 'U':
+                flags0 |= (UNICODE_CHARACTER_CLASS | UNICODE_CASE);
+                break;
+            case '-': // subFlag then fall through
+                ch = next();
+                subFlag();
+            default:
+                return;
+            }
+            ch = next();
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    /**
+     * Parses the second part of inlined match flags and turns off
+     * flags appropriately.
+     *
+    private void subFlag() {
+        int ch = peek();
+        for (;;) {
+            switch (ch) {
+            case 'i':
+                flags0 &= ~CASE_INSENSITIVE;
+                break;
+            case 'm':
+                flags0 &= ~MULTILINE;
+                break;
+            case 's':
+                flags0 &= ~DOTALL;
+                break;
+            case 'd':
+                flags0 &= ~UNIX_LINES;
+                break;
+            case 'u':
+                flags0 &= ~UNICODE_CASE;
+                break;
+            case 'c':
+                flags0 &= ~CANON_EQ;
+                break;
+            case 'x':
+                flags0 &= ~COMMENTS;
+                break;
+            case 'U':
+                flags0 &= ~(UNICODE_CHARACTER_CLASS | UNICODE_CASE);
+                break;
+            default:
+                return;
+            }
+            ch = next();
+        }
+    }
+
+    static final int MAX_REPS   = 0x7FFFFFFF;
+
+    static enum Qtype {
+        GREEDY, LAZY, POSSESSIVE, INDEPENDENT
+    }
+
+    private Qtype qtype() {
+        int ch = next();
+        if (ch == '?') {
+            next();
+            return Qtype.LAZY;
+        } else if (ch == '+') {
+            next();
+            return Qtype.POSSESSIVE;
+        }
+        return Qtype.GREEDY;
+    }
+
+    private Node curly(Node prev, int cmin) {
+        Qtype qtype = qtype();
+        if (qtype == Qtype.GREEDY) {
+            if (prev instanceof BmpCharProperty) {
+                return new BmpCharPropertyGreedy((BmpCharProperty)prev, cmin);
+            } else if (prev instanceof CharProperty) {
+                return new CharPropertyGreedy((CharProperty)prev, cmin);
+            }
+        }
+        return new Curly(prev, cmin, MAX_REPS, qtype);
+    }
+
+    /**
+     * Processes repetition. If the next character peeked is a quantifier
+     * then new nodes must be appended to handle the repetition.
+     * Prev could be a single or a group, so it could be a chain of nodes.
+     *
+    private Node closure(Node prev) {
+        int ch = peek();
+        switch (ch) {
+        case '?':
+            return new Ques(prev, qtype());
+        case '*':
+            return curly(prev, 0);
+        case '+':
+            return curly(prev, 1);
+        case '{':
+            ch = skip();
+            if (ASCII.isDigit(ch)) {
+                int cmin = 0, cmax;
+                try {
+                    do {
+                        cmin = Math.addExact(Math.multiplyExact(cmin, 10),
+                                             ch - '0');
+                    } while (ASCII.isDigit(ch = read()));
+                    if (ch == ',') {
+                        ch = read();
+                        if (ch == '}') {
+                            unread();
+                            return curly(prev, cmin);
+                        } else {
+                            cmax = 0;
+                            while (ASCII.isDigit(ch)) {
+                                cmax = Math.addExact(Math.multiplyExact(cmax, 10),
+                                                     ch - '0');
+                                ch = read();
+                            }
+                        }
+                    } else {
+                        cmax = cmin;
+                    }
+                } catch (ArithmeticException ae) {
+                    throw error("Illegal repetition range");
+                }
+                if (ch != '}')
+                    throw error("Unclosed counted closure");
+                if (cmax < cmin)
+                    throw error("Illegal repetition range");
+                unread();
+                return (cmin == 0 && cmax == 1)
+                        ? new Ques(prev, qtype())
+                        : new Curly(prev, cmin, cmax, qtype());
+            } else {
+                throw error("Illegal repetition");
+            }
+        default:
+            return prev;
+        }
+    }
+
+    /**
+     *  Utility method for parsing control escape sequences.
+     *
+    private int c() {
+        if (cursor < patternLength) {
+            return read() ^ 64;
+        }
+        throw error("Illegal control escape sequence");
+    }
+
+    /**
+     *  Utility method for parsing octal escape sequences.
+     *
+    private int o() {
+        int n = read();
+        if (((n-'0')|('7'-n)) >= 0) {
+            int m = read();
+            if (((m-'0')|('7'-m)) >= 0) {
+                int o = read();
+                if ((((o-'0')|('7'-o)) >= 0) && (((n-'0')|('3'-n)) >= 0)) {
+                    return (n - '0') * 64 + (m - '0') * 8 + (o - '0');
+                }
+                unread();
+                return (n - '0') * 8 + (m - '0');
+            }
+            unread();
+            return (n - '0');
+        }
+        throw error("Illegal octal escape sequence");
+    }
+
+    /**
+     *  Utility method for parsing hexadecimal escape sequences.
+     *
+    private int x() {
+        int n = read();
+        if (ASCII.isHexDigit(n)) {
+            int m = read();
+            if (ASCII.isHexDigit(m)) {
+                return ASCII.toDigit(n) * 16 + ASCII.toDigit(m);
+            }
+        } else if (n == '{' && ASCII.isHexDigit(peek())) {
+            int ch = 0;
+            while (ASCII.isHexDigit(n = read())) {
+                ch = (ch << 4) + ASCII.toDigit(n);
+                if (ch > Character.MAX_CODE_POINT)
+                    throw error("Hexadecimal codepoint is too big");
+            }
+            if (n != '}')
+                throw error("Unclosed hexadecimal escape sequence");
+            return ch;
+        }
+        throw error("Illegal hexadecimal escape sequence");
+    }
+
+    /**
+     *  Utility method for parsing unicode escape sequences.
+     *
+    private int cursor() {
+        return cursor;
+    }
+
+    private void setcursor(int pos) {
+        cursor = pos;
+    }
+
+    private int uxxxx() {
+        int n = 0;
+        for (int i = 0; i < 4; i++) {
+            int ch = read();
+            if (!ASCII.isHexDigit(ch)) {
+                throw error("Illegal Unicode escape sequence");
+            }
+            n = n * 16 + ASCII.toDigit(ch);
+        }
+        return n;
+    }
+
+    private int u() {
+        int n = uxxxx();
+        if (Character.isHighSurrogate((char)n)) {
+            int cur = cursor();
+            if (read() == '\\' && read() == 'u') {
+                int n2 = uxxxx();
+                if (Character.isLowSurrogate((char)n2))
+                    return Character.toCodePoint((char)n, (char)n2);
+            }
+            setcursor(cur);
+        }
+        return n;
+    }
+
+    private int N() {
+        if (read() == '{') {
+            int i = cursor;
+            while (read() != '}') {
+                if (cursor >= patternLength)
+                    throw error("Unclosed character name escape sequence");
+            }
+            String name = new String(temp, i, cursor - i - 1);
+            try {
+                return Character.codePointOf(name);
+            } catch (IllegalArgumentException x) {
+                throw error("Unknown character name [" + name + "]");
+            }
+        }
+        throw error("Illegal character name escape sequence");
+    }
+
+    //
+    // Utility methods for code point support
+    //
+    private static final int countChars(CharSequence seq, int index,
+                                        int lengthInCodePoints) {
+        // optimization
+        if (lengthInCodePoints == 1 && index >= 0 && index < seq.length() &&
+            !Character.isHighSurrogate(seq.charAt(index))) {
+            return 1;
+        }
+        int length = seq.length();
+        int x = index;
+        if (lengthInCodePoints >= 0) {
+            assert ((length == 0 && index == 0) || index >= 0 && index < length);
+            for (int i = 0; x < length && i < lengthInCodePoints; i++) {
+                if (Character.isHighSurrogate(seq.charAt(x++))) {
+                    if (x < length && Character.isLowSurrogate(seq.charAt(x))) {
+                        x++;
+                    }
+                }
+            }
+            return x - index;
+        }
+
+        assert (index >= 0 && index <= length);
+        if (index == 0) {
+            return 0;
+        }
+        int len = -lengthInCodePoints;
+        for (int i = 0; x > 0 && i < len; i++) {
+            if (Character.isLowSurrogate(seq.charAt(--x))) {
+                if (x > 0 && Character.isHighSurrogate(seq.charAt(x-1))) {
+                    x--;
+                }
+            }
+        }
+        return index - x;
+    }
+
+    private static final int countCodePoints(CharSequence seq) {
+        int length = seq.length();
+        int n = 0;
+        for (int i = 0; i < length; ) {
+            n++;
+            if (Character.isHighSurrogate(seq.charAt(i++))) {
+                if (i < length && Character.isLowSurrogate(seq.charAt(i))) {
+                    i++;
+                }
+            }
+        }
+        return n;
+    }
+
+    /**
+     *  Creates a bit vector for matching Latin-1 values. A normal BitClass
+     *  never matches values above Latin-1, and a complemented BitClass always
+     *  matches values above Latin-1.
+     *
+    static final class BitClass implements BmpCharPredicate {
+        final boolean[] bits;
+        BitClass() {
+            bits = new boolean[256];
+        }
+        BitClass add(int c, int flags) {
+            assert c >= 0 && c <= 255;
+            if ((flags & CASE_INSENSITIVE) != 0) {
+                if (ASCII.isAscii(c)) {
+                    bits[ASCII.toUpper(c)] = true;
+                    bits[ASCII.toLower(c)] = true;
+                } else if ((flags & UNICODE_CASE) != 0) {
+                    bits[Character.toLowerCase(c)] = true;
+                    bits[Character.toUpperCase(c)] = true;
+                }
+            }
+            bits[c] = true;
+            return this;
+        }
+        public boolean is(int ch) {
+            return ch < 256 && bits[ch];
+        }
+    }
+
+
+    /**
+     *  Utility method for creating a string slice matcher.
+     *
+    private Node newSlice(int[] buf, int count, boolean hasSupplementary) {
+        int[] tmp = new int[count];
+        if (has(CASE_INSENSITIVE)) {
+            if (has(UNICODE_CASE)) {
+                for (int i = 0; i < count; i++) {
+                    tmp[i] = Character.toLowerCase(
+                                 Character.toUpperCase(buf[i]));
+                }
+                return hasSupplementary? new SliceUS(tmp) : new SliceU(tmp);
+            }
+            for (int i = 0; i < count; i++) {
+                tmp[i] = ASCII.toLower(buf[i]);
+            }
+            return hasSupplementary? new SliceIS(tmp) : new SliceI(tmp);
+        }
+        for (int i = 0; i < count; i++) {
+            tmp[i] = buf[i];
+        }
+        return hasSupplementary ? new SliceS(tmp) : new Slice(tmp);
+    }
+    */
+    // END Android-removed: Reimplement matching logic via ICU4C.
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // Use native implementation instead of > 3000 lines of helper methods.
+    private void compile() throws PatternSyntaxException {
+        if (pattern == null) {
+            throw new NullPointerException("pattern == null");
+        }
+
+        String icuPattern = pattern;
+        if ((flags & LITERAL) != 0) {
+            icuPattern = quote(pattern);
+        }
+
+        // These are the flags natively supported by ICU.
+        // They even have the same value in native code.
+        int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
+        nativePattern = PatternNative.create(icuPattern, icuFlags);
+    }
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    // BEGIN Android-removed: Reimplement matching logic via ICU4C.
+    /**
+     * Node to anchor at the beginning of input. This object implements the
+     * match for a \A sequence, and the caret anchor will use this if not in
+     * multiline mode.
+     *
+    static final class Begin extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int fromIndex = (matcher.anchoringBounds) ?
+                matcher.from : 0;
+            if (i == fromIndex && next.match(matcher, i, seq)) {
+                matcher.first = i;
+                matcher.groups[0] = i;
+                matcher.groups[1] = matcher.last;
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Node to anchor at the end of input. This is the absolute end, so this
+     * should not match at the last newline before the end as $ will.
+     *
+    static final class End extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int endIndex = (matcher.anchoringBounds) ?
+                matcher.to : matcher.getTextLength();
+            if (i == endIndex) {
+                matcher.hitEnd = true;
+                return next.match(matcher, i, seq);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Node to anchor at the beginning of a line. This is essentially the
+     * object to match for the multiline ^.
+     *
+    static final class Caret extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int startIndex = matcher.from;
+            int endIndex = matcher.to;
+            if (!matcher.anchoringBounds) {
+                startIndex = 0;
+                endIndex = matcher.getTextLength();
+            }
+            // Perl does not match ^ at end of input even after newline
+            if (i == endIndex) {
+                matcher.hitEnd = true;
+                return false;
+            }
+            if (i > startIndex) {
+                char ch = seq.charAt(i-1);
+                if (ch != '\n' && ch != '\r'
+                    && (ch|1) != '\u2029'
+                    && ch != '\u0085' ) {
+                    return false;
+                }
+                // Should treat /r/n as one newline
+                if (ch == '\r' && seq.charAt(i) == '\n')
+                    return false;
+            }
+            return next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Node to anchor at the beginning of a line when in unixdot mode.
+     *
+    static final class UnixCaret extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int startIndex = matcher.from;
+            int endIndex = matcher.to;
+            if (!matcher.anchoringBounds) {
+                startIndex = 0;
+                endIndex = matcher.getTextLength();
+            }
+            // Perl does not match ^ at end of input even after newline
+            if (i == endIndex) {
+                matcher.hitEnd = true;
+                return false;
+            }
+            if (i > startIndex) {
+                char ch = seq.charAt(i-1);
+                if (ch != '\n') {
+                    return false;
+                }
+            }
+            return next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Node to match the location where the last match ended.
+     * This is used for the \G construct.
+     *
+    static final class LastMatch extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (i != matcher.oldLast)
+                return false;
+            return next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Node to anchor at the end of a line or the end of input based on the
+     * multiline mode.
+     *
+     * When not in multiline mode, the $ can only match at the very end
+     * of the input, unless the input ends in a line terminator in which
+     * it matches right before the last line terminator.
+     *
+     * Note that \r\n is considered an atomic line terminator.
+     *
+     * Like ^ the $ operator matches at a position, it does not match the
+     * line terminators themselves.
+     *
+    static final class Dollar extends Node {
+        boolean multiline;
+        Dollar(boolean mul) {
+            multiline = mul;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int endIndex = (matcher.anchoringBounds) ?
+                matcher.to : matcher.getTextLength();
+            if (!multiline) {
+                if (i < endIndex - 2)
+                    return false;
+                if (i == endIndex - 2) {
+                    char ch = seq.charAt(i);
+                    if (ch != '\r')
+                        return false;
+                    ch = seq.charAt(i + 1);
+                    if (ch != '\n')
+                        return false;
+                }
+            }
+            // Matches before any line terminator; also matches at the
+            // end of input
+            // Before line terminator:
+            // If multiline, we match here no matter what
+            // If not multiline, fall through so that the end
+            // is marked as hit; this must be a /r/n or a /n
+            // at the very end so the end was hit; more input
+            // could make this not match here
+            if (i < endIndex) {
+                char ch = seq.charAt(i);
+                 if (ch == '\n') {
+                     // No match between \r\n
+                     if (i > 0 && seq.charAt(i-1) == '\r')
+                         return false;
+                     if (multiline)
+                         return next.match(matcher, i, seq);
+                 } else if (ch == '\r' || ch == '\u0085' ||
+                            (ch|1) == '\u2029') {
+                     if (multiline)
+                         return next.match(matcher, i, seq);
+                 } else { // No line terminator, no match
+                     return false;
+                 }
+            }
+            // Matched at current end so hit end
+            matcher.hitEnd = true;
+            // If a $ matches because of end of input, then more input
+            // could cause it to fail!
+            matcher.requireEnd = true;
+            return next.match(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            next.study(info);
+            return info.deterministic;
+        }
+    }
+
+    /**
+     * Node to anchor at the end of a line or the end of input based on the
+     * multiline mode when in unix lines mode.
+     *
+    static final class UnixDollar extends Node {
+        boolean multiline;
+        UnixDollar(boolean mul) {
+            multiline = mul;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int endIndex = (matcher.anchoringBounds) ?
+                matcher.to : matcher.getTextLength();
+            if (i < endIndex) {
+                char ch = seq.charAt(i);
+                if (ch == '\n') {
+                    // If not multiline, then only possible to
+                    // match at very end or one before end
+                    if (multiline == false && i != endIndex - 1)
+                        return false;
+                    // If multiline return next.match without setting
+                    // matcher.hitEnd
+                    if (multiline)
+                        return next.match(matcher, i, seq);
+                } else {
+                    return false;
+                }
+            }
+            // Matching because at the end or 1 before the end;
+            // more input could change this so set hitEnd
+            matcher.hitEnd = true;
+            // If a $ matches because of end of input, then more input
+            // could cause it to fail!
+            matcher.requireEnd = true;
+            return next.match(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            next.study(info);
+            return info.deterministic;
+        }
+    }
+
+    /**
+     * Node class that matches a Unicode line ending '\R'
+     *
+    static final class LineEnding extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            // (u+000Du+000A|[u+000Au+000Bu+000Cu+000Du+0085u+2028u+2029])
+            if (i < matcher.to) {
+                int ch = seq.charAt(i);
+                if (ch == 0x0A || ch == 0x0B || ch == 0x0C ||
+                    ch == 0x85 || ch == 0x2028 || ch == 0x2029)
+                    return next.match(matcher, i + 1, seq);
+                if (ch == 0x0D) {
+                    i++;
+                    if (i < matcher.to) {
+                        if (seq.charAt(i) == 0x0A &&
+                            next.match(matcher, i + 1, seq)) {
+                            return true;
+                        }
+                    } else {
+                        matcher.hitEnd = true;
+                    }
+                    return next.match(matcher, i, seq);
+                }
+            } else {
+                matcher.hitEnd = true;
+            }
+            return false;
+        }
+        boolean study(TreeInfo info) {
+            info.minLength++;
+            info.maxLength += 2;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Abstract node class to match one character satisfying some
+     * boolean property.
+     *
+    static class CharProperty extends Node {
+        final CharPredicate predicate;
+
+        CharProperty (CharPredicate predicate) {
+            this.predicate = predicate;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (i < matcher.to) {
+                int ch = Character.codePointAt(seq, i);
+                i += Character.charCount(ch);
+                if (i <= matcher.to) {
+                    return predicate.is(ch) &&
+                           next.match(matcher, i, seq);
+                }
+            }
+            matcher.hitEnd = true;
+            return false;
+        }
+        boolean study(TreeInfo info) {
+            info.minLength++;
+            info.maxLength++;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Optimized version of CharProperty that works only for
+     * properties never satisfied by Supplementary characters.
+     *
+    private static class BmpCharProperty extends CharProperty {
+        BmpCharProperty (BmpCharPredicate predicate) {
+            super(predicate);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (i < matcher.to) {
+                return predicate.is(seq.charAt(i)) &&
+                       next.match(matcher, i + 1, seq);
+            } else {
+                matcher.hitEnd = true;
+                return false;
+            }
+        }
+    }
+
+    private static class NFCCharProperty extends Node {
+        CharPredicate predicate;
+        NFCCharProperty (CharPredicate predicate) {
+            this.predicate = predicate;
+        }
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (i < matcher.to) {
+                int ch0 = Character.codePointAt(seq, i);
+                int n = Character.charCount(ch0);
+                int j = Grapheme.nextBoundary(seq, i, matcher.to);
+                if (i + n == j) { // single cp grapheme, assume nfc
+                    if (predicate.is(ch0))
+                        return next.match(matcher, j, seq);
+                } else {
+                    while (i + n < j) {
+                        String nfc = Normalizer.normalize(
+                            seq.toString().substring(i, j), Normalizer.Form.NFC);
+                        if (nfc.codePointCount(0, nfc.length()) == 1) {
+                            if (predicate.is(nfc.codePointAt(0)) &&
+                                next.match(matcher, j, seq)) {
+                                return true;
+                            }
+                        }
+
+                        ch0 = Character.codePointBefore(seq, j);
+                        j -= Character.charCount(ch0);
+                    }
+                }
+                if (j < matcher.to)
+                    return false;
+            }
+            matcher.hitEnd = true;
+            return false;
+        }
+
+        boolean study(TreeInfo info) {
+            info.minLength++;
+            info.deterministic = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Node class that matches an unicode extended grapheme cluster
+     *
+    static class XGrapheme extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (i < matcher.to) {
+                i = Grapheme.nextBoundary(seq, i, matcher.to);
+                return next.match(matcher, i, seq);
+            }
+            matcher.hitEnd = true;
+            return false;
+        }
+
+        boolean study(TreeInfo info) {
+            info.minLength++;
+            info.deterministic = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Node class that handles grapheme boundaries
+     *
+    static class GraphemeBound extends Node {
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int startIndex = matcher.from;
+            int endIndex = matcher.to;
+            if (matcher.transparentBounds) {
+                startIndex = 0;
+                endIndex = matcher.getTextLength();
+            }
+            if (i == startIndex) {
+                // continue with return below
+            } else if (i < endIndex) {
+                if (Character.isSurrogatePair(seq.charAt(i - 1), seq.charAt(i))) {
+                    return false;
+                }
+                if (Grapheme.nextBoundary(seq, matcher.last, endIndex) > i) {
+                    return false;
+                }
+            } else {
+                matcher.hitEnd = true;
+                matcher.requireEnd = true;
+            }
+            return next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Base class for all Slice nodes
+     *
+    static class SliceNode extends Node {
+        int[] buffer;
+        SliceNode(int[] buf) {
+            buffer = buf;
+        }
+        boolean study(TreeInfo info) {
+            info.minLength += buffer.length;
+            info.maxLength += buffer.length;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Node class for a case sensitive/BMP-only sequence of literal
+     * characters.
+     *
+    static class Slice extends SliceNode {
+        Slice(int[] buf) {
+            super(buf);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] buf = buffer;
+            int len = buf.length;
+            for (int j=0; j<len; j++) {
+                if ((i+j) >= matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                if (buf[j] != seq.charAt(i+j))
+                    return false;
+            }
+            return next.match(matcher, i+len, seq);
+        }
+    }
+
+    /**
+     * Node class for a case_insensitive/BMP-only sequence of literal
+     * characters.
+     *
+    static class SliceI extends SliceNode {
+        SliceI(int[] buf) {
+            super(buf);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] buf = buffer;
+            int len = buf.length;
+            for (int j=0; j<len; j++) {
+                if ((i+j) >= matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                int c = seq.charAt(i+j);
+                if (buf[j] != c &&
+                    buf[j] != ASCII.toLower(c))
+                    return false;
+            }
+            return next.match(matcher, i+len, seq);
+        }
+    }
+
+    /**
+     * Node class for a unicode_case_insensitive/BMP-only sequence of
+     * literal characters. Uses unicode case folding.
+     *
+    static final class SliceU extends SliceNode {
+        SliceU(int[] buf) {
+            super(buf);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] buf = buffer;
+            int len = buf.length;
+            for (int j=0; j<len; j++) {
+                if ((i+j) >= matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                int c = seq.charAt(i+j);
+                if (buf[j] != c &&
+                    buf[j] != Character.toLowerCase(Character.toUpperCase(c)))
+                    return false;
+            }
+            return next.match(matcher, i+len, seq);
+        }
+    }
+
+    /**
+     * Node class for a case sensitive sequence of literal characters
+     * including supplementary characters.
+     *
+    static final class SliceS extends Slice {
+        SliceS(int[] buf) {
+            super(buf);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] buf = buffer;
+            int x = i;
+            for (int j = 0; j < buf.length; j++) {
+                if (x >= matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                int c = Character.codePointAt(seq, x);
+                if (buf[j] != c)
+                    return false;
+                x += Character.charCount(c);
+                if (x > matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+            }
+            return next.match(matcher, x, seq);
+        }
+    }
+
+    /**
+     * Node class for a case insensitive sequence of literal characters
+     * including supplementary characters.
+     *
+    static class SliceIS extends SliceNode {
+        SliceIS(int[] buf) {
+            super(buf);
+        }
+        int toLower(int c) {
+            return ASCII.toLower(c);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] buf = buffer;
+            int x = i;
+            for (int j = 0; j < buf.length; j++) {
+                if (x >= matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                int c = Character.codePointAt(seq, x);
+                if (buf[j] != c && buf[j] != toLower(c))
+                    return false;
+                x += Character.charCount(c);
+                if (x > matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+            }
+            return next.match(matcher, x, seq);
+        }
+    }
+
+    /**
+     * Node class for a case insensitive sequence of literal characters.
+     * Uses unicode case folding.
+     *
+    static final class SliceUS extends SliceIS {
+        SliceUS(int[] buf) {
+            super(buf);
+        }
+        int toLower(int c) {
+            return Character.toLowerCase(Character.toUpperCase(c));
+        }
+    }
+
+    /**
+     * The 0 or 1 quantifier. This one class implements all three types.
+     *
+    static final class Ques extends Node {
+        Node atom;
+        Qtype type;
+        Ques(Node node, Qtype type) {
+            this.atom = node;
+            this.type = type;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            switch (type) {
+            case GREEDY:
+                return (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq))
+                    || next.match(matcher, i, seq);
+            case LAZY:
+                return next.match(matcher, i, seq)
+                    || (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq));
+            case POSSESSIVE:
+                if (atom.match(matcher, i, seq)) i = matcher.last;
+                return next.match(matcher, i, seq);
+            default:
+                return atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq);
+            }
+        }
+        boolean study(TreeInfo info) {
+            if (type != Qtype.INDEPENDENT) {
+                int minL = info.minLength;
+                atom.study(info);
+                info.minLength = minL;
+                info.deterministic = false;
+                return next.study(info);
+            } else {
+                atom.study(info);
+                return next.study(info);
+            }
+        }
+    }
+
+    /**
+     * Handles the greedy style repetition with the specified minimum
+     * and the maximum equal to MAX_REPS, for *, + and {N,} quantifiers.
+     *
+    static class CharPropertyGreedy extends Node {
+        final CharPredicate predicate;
+        final int cmin;
+
+        CharPropertyGreedy(CharProperty cp, int cmin) {
+            this.predicate = cp.predicate;
+            this.cmin = cmin;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int starti = i;
+            int n = 0;
+            int to = matcher.to;
+            // greedy, all the way down
+            while (i < to) {
+                int ch = Character.codePointAt(seq, i);
+                int len = Character.charCount(ch);
+                if (i + len > to) {
+                    // the region cut off the high half of a surrogate pair
+                    matcher.hitEnd = true;
+                    ch = seq.charAt(i);
+                    len = 1;
+                }
+                if (!predicate.is(ch))
+                    break;
+                i += len;
+                n++;
+            }
+            if (i >= to) {
+                matcher.hitEnd = true;
+            }
+            while (n >= cmin) {
+                if (next.match(matcher, i, seq))
+                    return true;
+                if (n == cmin)
+                    return false;
+                // backing off if match fails
+                int ch = Character.codePointBefore(seq, i);
+                // check if the region cut off the low half of a surrogate pair
+                i = Math.max(starti, i - Character.charCount(ch));
+                n--;
+            }
+            return false;
+        }
+
+        boolean study(TreeInfo info) {
+            info.minLength += cmin;
+            if (info.maxValid) {
+                info.maxLength += MAX_REPS;
+            }
+            info.deterministic = false;
+            return next.study(info);
+        }
+    }
+
+    static final class BmpCharPropertyGreedy extends CharPropertyGreedy {
+
+        BmpCharPropertyGreedy(BmpCharProperty bcp, int cmin) {
+            super(bcp, cmin);
+        }
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int n = 0;
+            int to = matcher.to;
+            while (i < to && predicate.is(seq.charAt(i))) {
+                i++; n++;
+            }
+            if (i >= to) {
+                matcher.hitEnd = true;
+            }
+            while (n >= cmin) {
+                if (next.match(matcher, i, seq))
+                    return true;
+                i--; n--;  // backing off if match fails
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Handles the curly-brace style repetition with a specified minimum and
+     * maximum occurrences. The * quantifier is handled as a special case.
+     * This class handles the three types.
+     *
+    static final class Curly extends Node {
+        Node atom;
+        Qtype type;
+        int cmin;
+        int cmax;
+
+        Curly(Node node, int cmin, int cmax, Qtype type) {
+            this.atom = node;
+            this.type = type;
+            this.cmin = cmin;
+            this.cmax = cmax;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int j;
+            for (j = 0; j < cmin; j++) {
+                if (atom.match(matcher, i, seq)) {
+                    i = matcher.last;
+                    continue;
+                }
+                return false;
+            }
+            if (type == Qtype.GREEDY)
+                return match0(matcher, i, j, seq);
+            else if (type == Qtype.LAZY)
+                return match1(matcher, i, j, seq);
+            else
+                return match2(matcher, i, j, seq);
+        }
+        // Greedy match.
+        // i is the index to start matching at
+        // j is the number of atoms that have matched
+        boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
+            if (j >= cmax) {
+                // We have matched the maximum... continue with the rest of
+                // the regular expression
+                return next.match(matcher, i, seq);
+            }
+            int backLimit = j;
+            while (atom.match(matcher, i, seq)) {
+                // k is the length of this match
+                int k = matcher.last - i;
+                if (k == 0) // Zero length match
+                    break;
+                // Move up index and number matched
+                i = matcher.last;
+                j++;
+                // We are greedy so match as many as we can
+                while (j < cmax) {
+                    if (!atom.match(matcher, i, seq))
+                        break;
+                    if (i + k != matcher.last) {
+                        if (match0(matcher, matcher.last, j+1, seq))
+                            return true;
+                        break;
+                    }
+                    i += k;
+                    j++;
+                }
+                // Handle backing off if match fails
+                while (j >= backLimit) {
+                   if (next.match(matcher, i, seq))
+                        return true;
+                    i -= k;
+                    j--;
+                }
+                return false;
+            }
+            return next.match(matcher, i, seq);
+        }
+        // Reluctant match. At this point, the minimum has been satisfied.
+        // i is the index to start matching at
+        // j is the number of atoms that have matched
+        boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
+            for (;;) {
+                // Try finishing match without consuming any more
+                if (next.match(matcher, i, seq))
+                    return true;
+                // At the maximum, no match found
+                if (j >= cmax)
+                    return false;
+                // Okay, must try one more atom
+                if (!atom.match(matcher, i, seq))
+                    return false;
+                // If we haven't moved forward then must break out
+                if (i == matcher.last)
+                    return false;
+                // Move up index and number matched
+                i = matcher.last;
+                j++;
+            }
+        }
+        boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
+            for (; j < cmax; j++) {
+                if (!atom.match(matcher, i, seq))
+                    break;
+                if (i == matcher.last)
+                    break;
+                i = matcher.last;
+            }
+            return next.match(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            // Save original info
+            int minL = info.minLength;
+            int maxL = info.maxLength;
+            boolean maxV = info.maxValid;
+            boolean detm = info.deterministic;
+            info.reset();
+
+            atom.study(info);
+
+            int temp = info.minLength * cmin + minL;
+            if (temp < minL) {
+                temp = 0xFFFFFFF; // arbitrary large number
+            }
+            info.minLength = temp;
+
+            if (maxV & info.maxValid) {
+                temp = info.maxLength * cmax + maxL;
+                info.maxLength = temp;
+                if (temp < maxL) {
+                    info.maxValid = false;
+                }
+            } else {
+                info.maxValid = false;
+            }
+
+            if (info.deterministic && cmin == cmax)
+                info.deterministic = detm;
+            else
+                info.deterministic = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Handles the curly-brace style repetition with a specified minimum and
+     * maximum occurrences in deterministic cases. This is an iterative
+     * optimization over the Prolog and Loop system which would handle this
+     * in a recursive way. The * quantifier is handled as a special case.
+     * If capture is true then this class saves group settings and ensures
+     * that groups are unset when backing off of a group match.
+     *
+    static final class GroupCurly extends Node {
+        Node atom;
+        Qtype type;
+        int cmin;
+        int cmax;
+        int localIndex;
+        int groupIndex;
+        boolean capture;
+
+        GroupCurly(Node node, int cmin, int cmax, Qtype type, int local,
+                   int group, boolean capture) {
+            this.atom = node;
+            this.type = type;
+            this.cmin = cmin;
+            this.cmax = cmax;
+            this.localIndex = local;
+            this.groupIndex = group;
+            this.capture = capture;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] groups = matcher.groups;
+            int[] locals = matcher.locals;
+            int save0 = locals[localIndex];
+            int save1 = 0;
+            int save2 = 0;
+
+            if (capture) {
+                save1 = groups[groupIndex];
+                save2 = groups[groupIndex+1];
+            }
+
+            // Notify GroupTail there is no need to setup group info
+            // because it will be set here
+            locals[localIndex] = -1;
+
+            boolean ret = true;
+            for (int j = 0; j < cmin; j++) {
+                if (atom.match(matcher, i, seq)) {
+                    if (capture) {
+                        groups[groupIndex] = i;
+                        groups[groupIndex+1] = matcher.last;
+                    }
+                    i = matcher.last;
+                } else {
+                    ret = false;
+                    break;
+                }
+            }
+            if (ret) {
+                if (type == Qtype.GREEDY) {
+                    ret = match0(matcher, i, cmin, seq);
+                } else if (type == Qtype.LAZY) {
+                    ret = match1(matcher, i, cmin, seq);
+                } else {
+                    ret = match2(matcher, i, cmin, seq);
+                }
+            }
+            if (!ret) {
+                locals[localIndex] = save0;
+                if (capture) {
+                    groups[groupIndex] = save1;
+                    groups[groupIndex+1] = save2;
+                }
+            }
+            return ret;
+        }
+        // Aggressive group match
+        boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
+            // don't back off passing the starting "j"
+            int min = j;
+            int[] groups = matcher.groups;
+            int save0 = 0;
+            int save1 = 0;
+            if (capture) {
+                save0 = groups[groupIndex];
+                save1 = groups[groupIndex+1];
+            }
+            for (;;) {
+                if (j >= cmax)
+                    break;
+                if (!atom.match(matcher, i, seq))
+                    break;
+                int k = matcher.last - i;
+                if (k <= 0) {
+                    if (capture) {
+                        groups[groupIndex] = i;
+                        groups[groupIndex+1] = i + k;
+                    }
+                    i = i + k;
+                    break;
+                }
+                for (;;) {
+                    if (capture) {
+                        groups[groupIndex] = i;
+                        groups[groupIndex+1] = i + k;
+                    }
+                    i = i + k;
+                    if (++j >= cmax)
+                        break;
+                    if (!atom.match(matcher, i, seq))
+                        break;
+                    if (i + k != matcher.last) {
+                        if (match0(matcher, i, j, seq))
+                            return true;
+                        break;
+                    }
+                }
+                while (j > min) {
+                    if (next.match(matcher, i, seq)) {
+                        if (capture) {
+                            groups[groupIndex+1] = i;
+                            groups[groupIndex] = i - k;
+                        }
+                        return true;
+                    }
+                    // backing off
+                    i = i - k;
+                    if (capture) {
+                        groups[groupIndex+1] = i;
+                        groups[groupIndex] = i - k;
+                    }
+                    j--;
+
+                }
+                break;
+            }
+            if (capture) {
+                groups[groupIndex] = save0;
+                groups[groupIndex+1] = save1;
+            }
+            return next.match(matcher, i, seq);
+        }
+        // Reluctant matching
+        boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
+            for (;;) {
+                if (next.match(matcher, i, seq))
+                    return true;
+                if (j >= cmax)
+                    return false;
+                if (!atom.match(matcher, i, seq))
+                    return false;
+                if (i == matcher.last)
+                    return false;
+                if (capture) {
+                    matcher.groups[groupIndex] = i;
+                    matcher.groups[groupIndex+1] = matcher.last;
+                }
+                i = matcher.last;
+                j++;
+            }
+        }
+        // Possessive matching
+        boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
+            for (; j < cmax; j++) {
+                if (!atom.match(matcher, i, seq)) {
+                    break;
+                }
+                if (capture) {
+                    matcher.groups[groupIndex] = i;
+                    matcher.groups[groupIndex+1] = matcher.last;
+                }
+                if (i == matcher.last) {
+                    break;
+                }
+                i = matcher.last;
+            }
+            return next.match(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            // Save original info
+            int minL = info.minLength;
+            int maxL = info.maxLength;
+            boolean maxV = info.maxValid;
+            boolean detm = info.deterministic;
+            info.reset();
+
+            atom.study(info);
+
+            int temp = info.minLength * cmin + minL;
+            if (temp < minL) {
+                temp = 0xFFFFFFF; // Arbitrary large number
+            }
+            info.minLength = temp;
+
+            if (maxV & info.maxValid) {
+                temp = info.maxLength * cmax + maxL;
+                info.maxLength = temp;
+                if (temp < maxL) {
+                    info.maxValid = false;
+                }
+            } else {
+                info.maxValid = false;
+            }
+
+            if (info.deterministic && cmin == cmax) {
+                info.deterministic = detm;
+            } else {
+                info.deterministic = false;
+            }
+            return next.study(info);
+        }
+    }
+
+    /**
+     * A Guard node at the end of each atom node in a Branch. It
+     * serves the purpose of chaining the "match" operation to
+     * "next" but not the "study", so we can collect the TreeInfo
+     * of each atom node without including the TreeInfo of the
+     * "next".
+     *
+    static final class BranchConn extends Node {
+        BranchConn() {}
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            return next.match(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            return info.deterministic;
+        }
+    }
+
+    /**
+     * Handles the branching of alternations. Note this is also used for
+     * the ? quantifier to branch between the case where it matches once
+     * and where it does not occur.
+     *
+    static final class Branch extends Node {
+        Node[] atoms = new Node[2];
+        int size = 2;
+        Node conn;
+        Branch(Node first, Node second, Node branchConn) {
+            conn = branchConn;
+            atoms[0] = first;
+            atoms[1] = second;
+        }
+
+        void add(Node node) {
+            if (size >= atoms.length) {
+                Node[] tmp = new Node[atoms.length*2];
+                System.arraycopy(atoms, 0, tmp, 0, atoms.length);
+                atoms = tmp;
+            }
+            atoms[size++] = node;
+        }
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            for (int n = 0; n < size; n++) {
+                if (atoms[n] == null) {
+                    if (conn.next.match(matcher, i, seq))
+                        return true;
+                } else if (atoms[n].match(matcher, i, seq)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean study(TreeInfo info) {
+            int minL = info.minLength;
+            int maxL = info.maxLength;
+            boolean maxV = info.maxValid;
+
+            int minL2 = Integer.MAX_VALUE; //arbitrary large enough num
+            int maxL2 = -1;
+            for (int n = 0; n < size; n++) {
+                info.reset();
+                if (atoms[n] != null)
+                    atoms[n].study(info);
+                minL2 = Math.min(minL2, info.minLength);
+                maxL2 = Math.max(maxL2, info.maxLength);
+                maxV = (maxV & info.maxValid);
+            }
+
+            minL += minL2;
+            maxL += maxL2;
+
+            info.reset();
+            conn.next.study(info);
+
+            info.minLength += minL;
+            info.maxLength += maxL;
+            info.maxValid &= maxV;
+            info.deterministic = false;
+            return false;
+        }
+    }
+
+    /**
+     * The GroupHead saves the location where the group begins in the locals
+     * and restores them when the match is done.
+     *
+     * The matchRef is used when a reference to this group is accessed later
+     * in the expression. The locals will have a negative value in them to
+     * indicate that we do not want to unset the group if the reference
+     * doesn't match.
+     *
+    static final class GroupHead extends Node {
+        int localIndex;
+        GroupTail tail;    // for debug/print only, match does not need to know
+        GroupHead(int localCount) {
+            localIndex = localCount;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int save = matcher.locals[localIndex];
+            matcher.locals[localIndex] = i;
+            boolean ret = next.match(matcher, i, seq);
+            matcher.locals[localIndex] = save;
+            return ret;
+        }
+    }
+
+    /**
+     * The GroupTail handles the setting of group beginning and ending
+     * locations when groups are successfully matched. It must also be able to
+     * unset groups that have to be backed off of.
+     *
+     * The GroupTail node is also used when a previous group is referenced,
+     * and in that case no group information needs to be set.
+     *
+    static final class GroupTail extends Node {
+        int localIndex;
+        int groupIndex;
+        GroupTail(int localCount, int groupCount) {
+            localIndex = localCount;
+            groupIndex = groupCount + groupCount;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int tmp = matcher.locals[localIndex];
+            if (tmp >= 0) { // This is the normal group case.
+                // Save the group so we can unset it if it
+                // backs off of a match.
+                int groupStart = matcher.groups[groupIndex];
+                int groupEnd = matcher.groups[groupIndex+1];
+
+                matcher.groups[groupIndex] = tmp;
+                matcher.groups[groupIndex+1] = i;
+                if (next.match(matcher, i, seq)) {
+                    return true;
+                }
+                matcher.groups[groupIndex] = groupStart;
+                matcher.groups[groupIndex+1] = groupEnd;
+                return false;
+            } else {
+                // This is a group reference case. We don't need to save any
+                // group info because it isn't really a group.
+                matcher.last = i;
+                return true;
+            }
+        }
+    }
+
+    /**
+     * This sets up a loop to handle a recursive quantifier structure.
+     *
+    static final class Prolog extends Node {
+        Loop loop;
+        Prolog(Loop loop) {
+            this.loop = loop;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            return loop.matchInit(matcher, i, seq);
+        }
+        boolean study(TreeInfo info) {
+            return loop.study(info);
+        }
+    }
+
+    /**
+     * Handles the repetition count for a greedy Curly. The matchInit
+     * is called from the Prolog to save the index of where the group
+     * beginning is stored. A zero length group check occurs in the
+     * normal match but is skipped in the matchInit.
+     *
+    static class Loop extends Node {
+        Node body;
+        int countIndex; // local count index in matcher locals
+        int beginIndex; // group beginning index
+        int cmin, cmax;
+        int posIndex;
+        Loop(int countIndex, int beginIndex) {
+            this.countIndex = countIndex;
+            this.beginIndex = beginIndex;
+            this.posIndex = -1;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            // Avoid infinite loop in zero-length case.
+            if (i > matcher.locals[beginIndex]) {
+                int count = matcher.locals[countIndex];
+
+                // This block is for before we reach the minimum
+                // iterations required for the loop to match
+                if (count < cmin) {
+                    matcher.locals[countIndex] = count + 1;
+                    boolean b = body.match(matcher, i, seq);
+                    // If match failed we must backtrack, so
+                    // the loop count should NOT be incremented
+                    if (!b)
+                        matcher.locals[countIndex] = count;
+                    // Return success or failure since we are under
+                    // minimum
+                    return b;
+                }
+                // This block is for after we have the minimum
+                // iterations required for the loop to match
+                if (count < cmax) {
+                    // Let's check if we have already tried and failed
+                    // at this starting position "i" in the past.
+                    // If yes, then just return false wihtout trying
+                    // again, to stop the exponential backtracking.
+                    if (posIndex != -1 &&
+                        matcher.localsPos[posIndex].contains(i)) {
+                        return next.match(matcher, i, seq);
+                    }
+                    matcher.locals[countIndex] = count + 1;
+                    boolean b = body.match(matcher, i, seq);
+                    // If match failed we must backtrack, so
+                    // the loop count should NOT be incremented
+                    if (b)
+                        return true;
+                    matcher.locals[countIndex] = count;
+                    // save the failed position
+                    if (posIndex != -1) {
+                        matcher.localsPos[posIndex].add(i);
+                    }
+                }
+            }
+            return next.match(matcher, i, seq);
+        }
+        boolean matchInit(Matcher matcher, int i, CharSequence seq) {
+            int save = matcher.locals[countIndex];
+            boolean ret;
+            if (posIndex != -1 && matcher.localsPos[posIndex] == null) {
+                matcher.localsPos[posIndex] = new IntHashSet();
+            }
+            if (0 < cmin) {
+                matcher.locals[countIndex] = 1;
+                ret = body.match(matcher, i, seq);
+            } else if (0 < cmax) {
+                matcher.locals[countIndex] = 1;
+                ret = body.match(matcher, i, seq);
+                if (ret == false)
+                    ret = next.match(matcher, i, seq);
+            } else {
+                ret = next.match(matcher, i, seq);
+            }
+            matcher.locals[countIndex] = save;
+            return ret;
+        }
+        boolean study(TreeInfo info) {
+            info.maxValid = false;
+            info.deterministic = false;
+            return false;
+        }
+    }
+
+    /**
+     * Handles the repetition count for a reluctant Curly. The matchInit
+     * is called from the Prolog to save the index of where the group
+     * beginning is stored. A zero length group check occurs in the
+     * normal match but is skipped in the matchInit.
+     *
+    static final class LazyLoop extends Loop {
+        LazyLoop(int countIndex, int beginIndex) {
+            super(countIndex, beginIndex);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            // Check for zero length group
+            if (i > matcher.locals[beginIndex]) {
+                int count = matcher.locals[countIndex];
+                if (count < cmin) {
+                    matcher.locals[countIndex] = count + 1;
+                    boolean result = body.match(matcher, i, seq);
+                    // If match failed we must backtrack, so
+                    // the loop count should NOT be incremented
+                    if (!result)
+                        matcher.locals[countIndex] = count;
+                    return result;
+                }
+                if (next.match(matcher, i, seq))
+                    return true;
+                if (count < cmax) {
+                    matcher.locals[countIndex] = count + 1;
+                    boolean result = body.match(matcher, i, seq);
+                    // If match failed we must backtrack, so
+                    // the loop count should NOT be incremented
+                    if (!result)
+                        matcher.locals[countIndex] = count;
+                    return result;
+                }
+                return false;
+            }
+            return next.match(matcher, i, seq);
+        }
+        boolean matchInit(Matcher matcher, int i, CharSequence seq) {
+            int save = matcher.locals[countIndex];
+            boolean ret = false;
+            if (0 < cmin) {
+                matcher.locals[countIndex] = 1;
+                ret = body.match(matcher, i, seq);
+            } else if (next.match(matcher, i, seq)) {
+                ret = true;
+            } else if (0 < cmax) {
+                matcher.locals[countIndex] = 1;
+                ret = body.match(matcher, i, seq);
+            }
+            matcher.locals[countIndex] = save;
+            return ret;
+        }
+        boolean study(TreeInfo info) {
+            info.maxValid = false;
+            info.deterministic = false;
+            return false;
+        }
+    }
+
+    /**
+     * Refers to a group in the regular expression. Attempts to match
+     * whatever the group referred to last matched.
+     *
+    static class BackRef extends Node {
+        int groupIndex;
+        BackRef(int groupCount) {
+            super();
+            groupIndex = groupCount + groupCount;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int j = matcher.groups[groupIndex];
+            int k = matcher.groups[groupIndex+1];
+
+            int groupSize = k - j;
+            // If the referenced group didn't match, neither can this
+            if (j < 0)
+                return false;
+
+            // If there isn't enough input left no match
+            if (i + groupSize > matcher.to) {
+                matcher.hitEnd = true;
+                return false;
+            }
+            // Check each new char to make sure it matches what the group
+            // referenced matched last time around
+            for (int index=0; index<groupSize; index++)
+                if (seq.charAt(i+index) != seq.charAt(j+index))
+                    return false;
+
+            return next.match(matcher, i+groupSize, seq);
+        }
+        boolean study(TreeInfo info) {
+            info.maxValid = false;
+            return next.study(info);
+        }
+    }
+
+    static class CIBackRef extends Node {
+        int groupIndex;
+        boolean doUnicodeCase;
+        CIBackRef(int groupCount, boolean doUnicodeCase) {
+            super();
+            groupIndex = groupCount + groupCount;
+            this.doUnicodeCase = doUnicodeCase;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int j = matcher.groups[groupIndex];
+            int k = matcher.groups[groupIndex+1];
+
+            int groupSize = k - j;
+
+            // If the referenced group didn't match, neither can this
+            if (j < 0)
+                return false;
+
+            // If there isn't enough input left no match
+            if (i + groupSize > matcher.to) {
+                matcher.hitEnd = true;
+                return false;
+            }
+
+            // Check each new char to make sure it matches what the group
+            // referenced matched last time around
+            int x = i;
+            for (int index=0; index<groupSize; index++) {
+                int c1 = Character.codePointAt(seq, x);
+                int c2 = Character.codePointAt(seq, j);
+                if (c1 != c2) {
+                    if (doUnicodeCase) {
+                        int cc1 = Character.toUpperCase(c1);
+                        int cc2 = Character.toUpperCase(c2);
+                        if (cc1 != cc2 &&
+                            Character.toLowerCase(cc1) !=
+                            Character.toLowerCase(cc2))
+                            return false;
+                    } else {
+                        if (ASCII.toLower(c1) != ASCII.toLower(c2))
+                            return false;
+                    }
+                }
+                x += Character.charCount(c1);
+                j += Character.charCount(c2);
+            }
+
+            return next.match(matcher, i+groupSize, seq);
+        }
+        boolean study(TreeInfo info) {
+            info.maxValid = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Searches until the next instance of its atom. This is useful for
+     * finding the atom efficiently without passing an instance of it
+     * (greedy problem) and without a lot of wasted search time (reluctant
+     * problem).
+     *
+    static final class First extends Node {
+        Node atom;
+        First(Node node) {
+            this.atom = BnM.optimize(node);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            if (atom instanceof BnM) {
+                return atom.match(matcher, i, seq)
+                    && next.match(matcher, matcher.last, seq);
+            }
+            for (;;) {
+                if (i > matcher.to) {
+                    matcher.hitEnd = true;
+                    return false;
+                }
+                if (atom.match(matcher, i, seq)) {
+                    return next.match(matcher, matcher.last, seq);
+                }
+                i += countChars(seq, i, 1);
+                matcher.first++;
+            }
+        }
+        boolean study(TreeInfo info) {
+            atom.study(info);
+            info.maxValid = false;
+            info.deterministic = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Zero width positive lookahead.
+     *
+    static final class Pos extends Node {
+        Node cond;
+        Pos(Node cond) {
+            this.cond = cond;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int savedTo = matcher.to;
+            boolean conditionMatched;
+
+            // Relax transparent region boundaries for lookahead
+            if (matcher.transparentBounds)
+                matcher.to = matcher.getTextLength();
+            try {
+                conditionMatched = cond.match(matcher, i, seq);
+            } finally {
+                // Reinstate region boundaries
+                matcher.to = savedTo;
+            }
+            return conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Zero width negative lookahead.
+     *
+    static final class Neg extends Node {
+        Node cond;
+        Neg(Node cond) {
+            this.cond = cond;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int savedTo = matcher.to;
+            boolean conditionMatched;
+
+            // Relax transparent region boundaries for lookahead
+            if (matcher.transparentBounds)
+                matcher.to = matcher.getTextLength();
+            try {
+                if (i < matcher.to) {
+                    conditionMatched = !cond.match(matcher, i, seq);
+                } else {
+                    // If a negative lookahead succeeds then more input
+                    // could cause it to fail!
+                    matcher.requireEnd = true;
+                    conditionMatched = !cond.match(matcher, i, seq);
+                }
+            } finally {
+                // Reinstate region boundaries
+                matcher.to = savedTo;
+            }
+            return conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * For use with lookbehinds; matches the position where the lookbehind
+     * was encountered.
+     *
+    static class LookBehindEndNode extends Node {
+        private LookBehindEndNode() {} // Singleton
+
+        static LookBehindEndNode INSTANCE = new LookBehindEndNode();
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            return i == matcher.lookbehindTo;
+        }
+    }
+
+    /**
+     * Zero width positive lookbehind.
+     *
+    static class Behind extends Node {
+        Node cond;
+        int rmax, rmin;
+        Behind(Node cond, int rmax, int rmin) {
+            this.cond = cond;
+            this.rmax = rmax;
+            this.rmin = rmin;
+        }
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int savedFrom = matcher.from;
+            boolean conditionMatched = false;
+            int startIndex = (!matcher.transparentBounds) ?
+                             matcher.from : 0;
+            int from = Math.max(i - rmax, startIndex);
+            // Set end boundary
+            int savedLBT = matcher.lookbehindTo;
+            matcher.lookbehindTo = i;
+            // Relax transparent region boundaries for lookbehind
+            if (matcher.transparentBounds)
+                matcher.from = 0;
+            for (int j = i - rmin; !conditionMatched && j >= from; j--) {
+                conditionMatched = cond.match(matcher, j, seq);
+            }
+            matcher.from = savedFrom;
+            matcher.lookbehindTo = savedLBT;
+            return conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Zero width positive lookbehind, including supplementary
+     * characters or unpaired surrogates.
+     *
+    static final class BehindS extends Behind {
+        BehindS(Node cond, int rmax, int rmin) {
+            super(cond, rmax, rmin);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int rmaxChars = countChars(seq, i, -rmax);
+            int rminChars = countChars(seq, i, -rmin);
+            int savedFrom = matcher.from;
+            int startIndex = (!matcher.transparentBounds) ?
+                             matcher.from : 0;
+            boolean conditionMatched = false;
+            int from = Math.max(i - rmaxChars, startIndex);
+            // Set end boundary
+            int savedLBT = matcher.lookbehindTo;
+            matcher.lookbehindTo = i;
+            // Relax transparent region boundaries for lookbehind
+            if (matcher.transparentBounds)
+                matcher.from = 0;
+
+            for (int j = i - rminChars;
+                 !conditionMatched && j >= from;
+                 j -= j>from ? countChars(seq, j, -1) : 1) {
+                conditionMatched = cond.match(matcher, j, seq);
+            }
+            matcher.from = savedFrom;
+            matcher.lookbehindTo = savedLBT;
+            return conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Zero width negative lookbehind.
+     *
+    static class NotBehind extends Node {
+        Node cond;
+        int rmax, rmin;
+        NotBehind(Node cond, int rmax, int rmin) {
+            this.cond = cond;
+            this.rmax = rmax;
+            this.rmin = rmin;
+        }
+
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int savedLBT = matcher.lookbehindTo;
+            int savedFrom = matcher.from;
+            boolean conditionMatched = false;
+            int startIndex = (!matcher.transparentBounds) ?
+                             matcher.from : 0;
+            int from = Math.max(i - rmax, startIndex);
+            matcher.lookbehindTo = i;
+            // Relax transparent region boundaries for lookbehind
+            if (matcher.transparentBounds)
+                matcher.from = 0;
+            for (int j = i - rmin; !conditionMatched && j >= from; j--) {
+                conditionMatched = cond.match(matcher, j, seq);
+            }
+            // Reinstate region boundaries
+            matcher.from = savedFrom;
+            matcher.lookbehindTo = savedLBT;
+            return !conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Zero width negative lookbehind, including supplementary
+     * characters or unpaired surrogates.
+     *
+    static final class NotBehindS extends NotBehind {
+        NotBehindS(Node cond, int rmax, int rmin) {
+            super(cond, rmax, rmin);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int rmaxChars = countChars(seq, i, -rmax);
+            int rminChars = countChars(seq, i, -rmin);
+            int savedFrom = matcher.from;
+            int savedLBT = matcher.lookbehindTo;
+            boolean conditionMatched = false;
+            int startIndex = (!matcher.transparentBounds) ?
+                             matcher.from : 0;
+            int from = Math.max(i - rmaxChars, startIndex);
+            matcher.lookbehindTo = i;
+            // Relax transparent region boundaries for lookbehind
+            if (matcher.transparentBounds)
+                matcher.from = 0;
+            for (int j = i - rminChars;
+                 !conditionMatched && j >= from;
+                 j -= j>from ? countChars(seq, j, -1) : 1) {
+                conditionMatched = cond.match(matcher, j, seq);
+            }
+            //Reinstate region boundaries
+            matcher.from = savedFrom;
+            matcher.lookbehindTo = savedLBT;
+            return !conditionMatched && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Handles word boundaries. Includes a field to allow this one class to
+     * deal with the different types of word boundaries we can match. The word
+     * characters include underscores, letters, and digits. Non spacing marks
+     * can are also part of a word if they have a base character, otherwise
+     * they are ignored for purposes of finding word boundaries.
+     *
+    static final class Bound extends Node {
+        static int LEFT = 0x1;
+        static int RIGHT= 0x2;
+        static int BOTH = 0x3;
+        static int NONE = 0x4;
+        int type;
+        boolean useUWORD;
+        Bound(int n, boolean useUWORD) {
+            type = n;
+            this.useUWORD = useUWORD;
+        }
+
+        boolean isWord(int ch) {
+            return useUWORD ? CharPredicates.WORD().is(ch)
+                            : (ch == '_' || Character.isLetterOrDigit(ch));
+        }
+
+        int check(Matcher matcher, int i, CharSequence seq) {
+            int ch;
+            boolean left = false;
+            int startIndex = matcher.from;
+            int endIndex = matcher.to;
+            if (matcher.transparentBounds) {
+                startIndex = 0;
+                endIndex = matcher.getTextLength();
+            }
+            if (i > startIndex) {
+                ch = Character.codePointBefore(seq, i);
+                left = (isWord(ch) ||
+                    ((Character.getType(ch) == Character.NON_SPACING_MARK)
+                     && hasBaseCharacter(matcher, i-1, seq)));
+            }
+            boolean right = false;
+            if (i < endIndex) {
+                ch = Character.codePointAt(seq, i);
+                right = (isWord(ch) ||
+                    ((Character.getType(ch) == Character.NON_SPACING_MARK)
+                     && hasBaseCharacter(matcher, i, seq)));
+            } else {
+                // Tried to access char past the end
+                matcher.hitEnd = true;
+                // The addition of another char could wreck a boundary
+                matcher.requireEnd = true;
+            }
+            return ((left ^ right) ? (right ? LEFT : RIGHT) : NONE);
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            return (check(matcher, i, seq) & type) > 0
+                && next.match(matcher, i, seq);
+        }
+    }
+
+    /**
+     * Non spacing marks only count as word characters in bounds calculations
+     * if they have a base character.
+     *
+    private static boolean hasBaseCharacter(Matcher matcher, int i,
+                                            CharSequence seq)
+    {
+        int start = (!matcher.transparentBounds) ?
+            matcher.from : 0;
+        for (int x=i; x >= start; x--) {
+            int ch = Character.codePointAt(seq, x);
+            if (Character.isLetterOrDigit(ch))
+                return true;
+            if (Character.getType(ch) == Character.NON_SPACING_MARK)
+                continue;
+            return false;
+        }
+        return false;
+    }
+
+    /**
+     * Attempts to match a slice in the input using the Boyer-Moore string
+     * matching algorithm. The algorithm is based on the idea that the
+     * pattern can be shifted farther ahead in the search text if it is
+     * matched right to left.
+     * <p>
+     * The pattern is compared to the input one character at a time, from
+     * the rightmost character in the pattern to the left. If the characters
+     * all match the pattern has been found. If a character does not match,
+     * the pattern is shifted right a distance that is the maximum of two
+     * functions, the bad character shift and the good suffix shift. This
+     * shift moves the attempted match position through the input more
+     * quickly than a naive one position at a time check.
+     * <p>
+     * The bad character shift is based on the character from the text that
+     * did not match. If the character does not appear in the pattern, the
+     * pattern can be shifted completely beyond the bad character. If the
+     * character does occur in the pattern, the pattern can be shifted to
+     * line the pattern up with the next occurrence of that character.
+     * <p>
+     * The good suffix shift is based on the idea that some subset on the right
+     * side of the pattern has matched. When a bad character is found, the
+     * pattern can be shifted right by the pattern length if the subset does
+     * not occur again in pattern, or by the amount of distance to the
+     * next occurrence of the subset in the pattern.
+     *
+     * Boyer-Moore search methods adapted from code by Amy Yu.
+     *
+    static class BnM extends Node {
+        int[] buffer;
+        int[] lastOcc;
+        int[] optoSft;
+
+        /**
+         * Pre calculates arrays needed to generate the bad character
+         * shift and the good suffix shift. Only the last seven bits
+         * are used to see if chars match; This keeps the tables small
+         * and covers the heavily used ASCII range, but occasionally
+         * results in an aliased match for the bad character shift.
+         *
+        static Node optimize(Node node) {
+            if (!(node instanceof Slice)) {
+                return node;
+            }
+
+            int[] src = ((Slice) node).buffer;
+            int patternLength = src.length;
+            // The BM algorithm requires a bit of overhead;
+            // If the pattern is short don't use it, since
+            // a shift larger than the pattern length cannot
+            // be used anyway.
+            if (patternLength < 4) {
+                return node;
+            }
+            int i, j;
+            int[] lastOcc = new int[128];
+            int[] optoSft = new int[patternLength];
+            // Precalculate part of the bad character shift
+            // It is a table for where in the pattern each
+            // lower 7-bit value occurs
+            for (i = 0; i < patternLength; i++) {
+                lastOcc[src[i]&0x7F] = i + 1;
+            }
+            // Precalculate the good suffix shift
+            // i is the shift amount being considered
+NEXT:       for (i = patternLength; i > 0; i--) {
+                // j is the beginning index of suffix being considered
+                for (j = patternLength - 1; j >= i; j--) {
+                    // Testing for good suffix
+                    if (src[j] == src[j-i]) {
+                        // src[j..len] is a good suffix
+                        optoSft[j-1] = i;
+                    } else {
+                        // No match. The array has already been
+                        // filled up with correct values before.
+                        continue NEXT;
+                    }
+                }
+                // This fills up the remaining of optoSft
+                // any suffix can not have larger shift amount
+                // then its sub-suffix. Why???
+                while (j > 0) {
+                    optoSft[--j] = i;
+                }
+            }
+            // Set the guard value because of unicode compression
+            optoSft[patternLength-1] = 1;
+            if (node instanceof SliceS)
+                return new BnMS(src, lastOcc, optoSft, node.next);
+            return new BnM(src, lastOcc, optoSft, node.next);
+        }
+        BnM(int[] src, int[] lastOcc, int[] optoSft, Node next) {
+            this.buffer = src;
+            this.lastOcc = lastOcc;
+            this.optoSft = optoSft;
+            this.next = next;
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] src = buffer;
+            int patternLength = src.length;
+            int last = matcher.to - patternLength;
+
+            // Loop over all possible match positions in text
+NEXT:       while (i <= last) {
+                // Loop over pattern from right to left
+                for (int j = patternLength - 1; j >= 0; j--) {
+                    int ch = seq.charAt(i+j);
+                    if (ch != src[j]) {
+                        // Shift search to the right by the maximum of the
+                        // bad character shift and the good suffix shift
+                        i += Math.max(j + 1 - lastOcc[ch&0x7F], optoSft[j]);
+                        continue NEXT;
+                    }
+                }
+                // Entire pattern matched starting at i
+                matcher.first = i;
+                boolean ret = next.match(matcher, i + patternLength, seq);
+                if (ret) {
+                    matcher.first = i;
+                    matcher.groups[0] = matcher.first;
+                    matcher.groups[1] = matcher.last;
+                    return true;
+                }
+                i++;
+            }
+            // BnM is only used as the leading node in the unanchored case,
+            // and it replaced its Start() which always searches to the end
+            // if it doesn't find what it's looking for, so hitEnd is true.
+            matcher.hitEnd = true;
+            return false;
+        }
+        boolean study(TreeInfo info) {
+            info.minLength += buffer.length;
+            info.maxValid = false;
+            return next.study(info);
+        }
+    }
+
+    /**
+     * Supplementary support version of BnM(). Unpaired surrogates are
+     * also handled by this class.
+     *
+    static final class BnMS extends BnM {
+        int lengthInChars;
+
+        BnMS(int[] src, int[] lastOcc, int[] optoSft, Node next) {
+            super(src, lastOcc, optoSft, next);
+            for (int cp : buffer) {
+                lengthInChars += Character.charCount(cp);
+            }
+        }
+        boolean match(Matcher matcher, int i, CharSequence seq) {
+            int[] src = buffer;
+            int patternLength = src.length;
+            int last = matcher.to - lengthInChars;
+
+            // Loop over all possible match positions in text
+NEXT:       while (i <= last) {
+                // Loop over pattern from right to left
+                int ch;
+                for (int j = countChars(seq, i, patternLength), x = patternLength - 1;
+                     j > 0; j -= Character.charCount(ch), x--) {
+                    ch = Character.codePointBefore(seq, i+j);
+                    if (ch != src[x]) {
+                        // Shift search to the right by the maximum of the
+                        // bad character shift and the good suffix shift
+                        int n = Math.max(x + 1 - lastOcc[ch&0x7F], optoSft[x]);
+                        i += countChars(seq, i, n);
+                        continue NEXT;
+                    }
+                }
+                // Entire pattern matched starting at i
+                matcher.first = i;
+                boolean ret = next.match(matcher, i + lengthInChars, seq);
+                if (ret) {
+                    matcher.first = i;
+                    matcher.groups[0] = matcher.first;
+                    matcher.groups[1] = matcher.last;
+                    return true;
+                }
+                i += countChars(seq, i, 1);
+            }
+            matcher.hitEnd = true;
+            return false;
+        }
+    }
+
+    @FunctionalInterface
+    static interface CharPredicate {
+        boolean is(int ch);
+
+        default CharPredicate and(CharPredicate p) {
+            return ch -> is(ch) && p.is(ch);
+        }
+        default CharPredicate union(CharPredicate p) {
+            return ch -> is(ch) || p.is(ch);
+        }
+        default CharPredicate union(CharPredicate p1,
+                                    CharPredicate p2) {
+            return ch -> is(ch) || p1.is(ch) || p2.is(ch);
+        }
+        default CharPredicate negate() {
+            return ch -> !is(ch);
+        }
+    }
+
+    static interface BmpCharPredicate extends CharPredicate {
+
+        default CharPredicate and(CharPredicate p) {
+            if (p instanceof BmpCharPredicate)
+                return (BmpCharPredicate)(ch -> is(ch) && p.is(ch));
+            return ch -> is(ch) && p.is(ch);
+        }
+        default CharPredicate union(CharPredicate p) {
+            if (p instanceof BmpCharPredicate)
+                return (BmpCharPredicate)(ch -> is(ch) || p.is(ch));
+            return ch -> is(ch) || p.is(ch);
+        }
+        static CharPredicate union(CharPredicate... predicates) {
+            CharPredicate cp = ch -> {
+                for (CharPredicate p : predicates) {
+                    if (!p.is(ch))
+                        return false;
+                }
+                return true;
+            };
+            for (CharPredicate p : predicates) {
+                if (! (p instanceof BmpCharPredicate))
+                    return cp;
+            }
+            return (BmpCharPredicate)cp;
+        }
+    }
+
+    /**
+     * matches a Perl vertical whitespace
+     *
+    static BmpCharPredicate VertWS() {
+        return cp -> (cp >= 0x0A && cp <= 0x0D) ||
+            cp == 0x85 || cp == 0x2028 || cp == 0x2029;
+    }
+
+    /**
+     * matches a Perl horizontal whitespace
+     *
+    static BmpCharPredicate HorizWS() {
+        return cp ->
+            cp == 0x09 || cp == 0x20 || cp == 0xa0 || cp == 0x1680 ||
+            cp == 0x180e || cp >= 0x2000 && cp <= 0x200a ||  cp == 0x202f ||
+            cp == 0x205f || cp == 0x3000;
+    }
+
+    /**
+     *  for the Unicode category ALL and the dot metacharacter when
+     *  in dotall mode.
+     *
+    static CharPredicate ALL() {
+        return ch -> true;
+    }
+
+    /**
+     * for the dot metacharacter when dotall is not enabled.
+     *
+    static CharPredicate DOT() {
+        return ch ->
+            (ch != '\n' && ch != '\r'
+            && (ch|1) != '\u2029'
+            && ch != '\u0085');
+    }
+
+    /**
+     *  the dot metacharacter when dotall is not enabled but UNIX_LINES is enabled.
+     *
+    static CharPredicate UNIXDOT() {
+        return ch ->  ch != '\n';
+    }
+
+    /**
+     * Indicate that matches a Supplementary Unicode character
+     *
+    static CharPredicate SingleS(int c) {
+        return ch -> ch == c;
+    }
+
+    /**
+     * A bmp/optimized predicate of single
+     *
+    static BmpCharPredicate Single(int c) {
+        return ch -> ch == c;
+    }
+
+    /**
+     * Case insensitive matches a given BMP character
+     *
+    static BmpCharPredicate SingleI(int lower, int upper) {
+        return ch -> ch == lower || ch == upper;
+    }
+
+    /**
+     * Unicode case insensitive matches a given Unicode character
+     *
+    static CharPredicate SingleU(int lower) {
+        return ch -> lower == ch ||
+                     lower == Character.toLowerCase(Character.toUpperCase(ch));
+    }
+
+    private static boolean inRange(int lower, int ch, int upper) {
+        return lower <= ch && ch <= upper;
+    }
+
+    /**
+     * Characters within a explicit value range
+     *
+    static CharPredicate Range(int lower, int upper) {
+        if (upper < Character.MIN_HIGH_SURROGATE ||
+            lower > Character.MAX_LOW_SURROGATE &&
+            upper < Character.MIN_SUPPLEMENTARY_CODE_POINT)
+            return (BmpCharPredicate)(ch -> inRange(lower, ch, upper));
+        return ch -> inRange(lower, ch, upper);
+    }
+
+   /**
+    * Characters within a explicit value range in a case insensitive manner.
+    *
+    static CharPredicate CIRange(int lower, int upper) {
+        return ch -> inRange(lower, ch, upper) ||
+                     ASCII.isAscii(ch) &&
+                     (inRange(lower, ASCII.toUpper(ch), upper) ||
+                      inRange(lower, ASCII.toLower(ch), upper));
+    }
+
+    static CharPredicate CIRangeU(int lower, int upper) {
+        return ch -> {
+            if (inRange(lower, ch, upper))
+                return true;
+            int up = Character.toUpperCase(ch);
+            return inRange(lower, up, upper) ||
+                   inRange(lower, Character.toLowerCase(up), upper);
+        };
+    }
+
+    /**
+     *  This must be the very first initializer.
+     *
+    static final Node accept = new Node();
+
+    static final Node lastAccept = new LastNode();
+    */
+    // END Android-removed: Reimplement matching logic via ICU4C.
+
+    /**
+     * Creates a predicate that tests if this pattern is found in a given input
+     * string.
+     *
+     * @apiNote
+     * This method creates a predicate that behaves as if it creates a matcher
+     * from the input sequence and then calls {@code find}, for example a
+     * predicate of the form:
+     * <pre>{@code
+     *   s -> matcher(s).find();
+     * }</pre>
+     *
+     * @return  The predicate which can be used for finding a match on a
+     *          subsequence of a string
+     * @since   1.8
+     * @see     Matcher#find
+     */
+    public Predicate<String> asPredicate() {
+        return s -> matcher(s).find();
+    }
+
+    /**
+     * Creates a predicate that tests if this pattern matches a given input string.
+     *
+     * @apiNote
+     * This method creates a predicate that behaves as if it creates a matcher
+     * from the input sequence and then calls {@code matches}, for example a
+     * predicate of the form:
+     * <pre>{@code
+     *   s -> matcher(s).matches();
+     * }</pre>
+     *
+     * @return  The predicate which can be used for matching an input string
+     *          against this pattern.
+     * @since   11
+     * @see     Matcher#matches
+     */
+    public Predicate<String> asMatchPredicate() {
+        return s -> matcher(s).matches();
+    }
+
+    /**
+     * Creates a stream from the given input sequence around matches of this
+     * pattern.
+     *
+     * <p> The stream returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the stream are in the order in which they occur in the
+     * input. Trailing empty strings will be discarded and not encountered in
+     * the stream.
+     *
+     * <p> If this pattern does not match any subsequence of the input then
+     * the resulting stream has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the stream. A zero-width match at the beginning however never produces
+     * such empty leading substring.
+     *
+     * <p> If the input sequence is mutable, it must remain constant during the
+     * execution of the terminal stream operation.  Otherwise, the result of the
+     * terminal stream operation is undefined.
+     *
+     * @param   input
+     *          The character sequence to be split
+     *
+     * @return  The stream of strings computed by splitting the input
+     *          around matches of this pattern
+     * @see     #split(CharSequence)
+     * @since   1.8
+     */
+    public Stream<String> splitAsStream(final CharSequence input) {
+        class MatcherIterator implements Iterator<String> {
+            private Matcher matcher;
+            // The start position of the next sub-sequence of input
+            // when current == input.length there are no more elements
+            private int current;
+            // null if the next element, if any, needs to obtained
+            private String nextElement;
+            // > 0 if there are N next empty elements
+            private int emptyElementCount;
+
+            public String next() {
+                if (!hasNext())
+                    throw new NoSuchElementException();
+
+                if (emptyElementCount == 0) {
+                    String n = nextElement;
+                    nextElement = null;
+                    return n;
+                } else {
+                    emptyElementCount--;
+                    return "";
+                }
+            }
+
+            public boolean hasNext() {
+                if (matcher == null) {
+                    matcher = matcher(input);
+                    // If the input is an empty string then the result can only be a
+                    // stream of the input.  Induce that by setting the empty
+                    // element count to 1
+                    // Android-changed: Keep old behavior on Android 13 or below. http://b/286499139
+                    // emptyElementCount = input.length() == 0 ? 1 : 0;
+                    if (input.length() == 0
+                            && VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE
+                            && Compatibility.isChangeEnabled(
+                                    SPLIT_AS_STREAM_RETURNS_SINGLE_EMPTY_STRING)) {
+                        emptyElementCount = 1;
+                    } else {
+                        emptyElementCount = 0;
+                    }
+                }
+                if (nextElement != null || emptyElementCount > 0)
+                    return true;
+
+                if (current == input.length())
+                    return false;
+
+                // Consume the next matching element
+                // Count sequence of matching empty elements
+                while (matcher.find()) {
+                    nextElement = input.subSequence(current, matcher.start()).toString();
+                    current = matcher.end();
+                    if (!nextElement.isEmpty()) {
+                        return true;
+                    } else if (current > 0) { // no empty leading substring for zero-width
+                                              // match at the beginning of the input
+                        emptyElementCount++;
+                    }
+                }
+
+                // Consume last matching element
+                nextElement = input.subSequence(current, input.length()).toString();
+                current = input.length();
+                if (!nextElement.isEmpty()) {
+                    return true;
+                } else {
+                    // Ignore a terminal sequence of matching empty elements
+                    emptyElementCount = 0;
+                    nextElement = null;
+                    return false;
+                }
+            }
+        }
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                new MatcherIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+
+    //  Android-added: Backward-compatible flag for splitAsStream() API.
+    /**
+     * Since Android 14, {@link Pattern#splitAsStream(CharSequence)} return a stream of a single
+     * empty String as described in the API documentation. Previously, given an empty string input,
+     * the method returns an empty stream.
+     *
+     * This flag is enabled for apps targeting Android 14+.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VersionCodes.UPSIDE_DOWN_CAKE)
+    public static final long SPLIT_AS_STREAM_RETURNS_SINGLE_EMPTY_STRING = 288845345L;
+
+}
diff --git a/android-35/java/util/regex/PatternSyntaxException.java b/android-35/java/util/regex/PatternSyntaxException.java
new file mode 100644
index 0000000..2b5da62
--- /dev/null
+++ b/android-35/java/util/regex/PatternSyntaxException.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+/**
+ * Unchecked exception thrown to indicate a syntax error in a
+ * regular-expression pattern.
+ *
+ * @since 1.4
+ */
+
+public class PatternSyntaxException
+    extends IllegalArgumentException
+{
+    @java.io.Serial
+    private static final long serialVersionUID = -3864639126226059218L;
+
+    private final String desc;
+    private final String pattern;
+    private final int index;
+
+    /**
+     * Constructs a new instance of this class.
+     *
+     * @param  desc
+     *         A description of the error
+     *
+     * @param  regex
+     *         The erroneous pattern
+     *
+     * @param  index
+     *         The approximate index in the pattern of the error,
+     *         or {@code -1} if the index is not known
+     */
+    public PatternSyntaxException(String desc, String regex, int index) {
+        this.desc = desc;
+        this.pattern = regex;
+        this.index = index;
+    }
+
+    /**
+     * Retrieves the error index.
+     *
+     * @return  The approximate index in the pattern of the error,
+     *         or {@code -1} if the index is not known
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Retrieves the description of the error.
+     *
+     * @return  The description of the error
+     */
+    public String getDescription() {
+        return desc;
+    }
+
+    /**
+     * Retrieves the erroneous regular-expression pattern.
+     *
+     * @return  The erroneous pattern
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Returns a multi-line string containing the description of the syntax
+     * error and its index, the erroneous regular-expression pattern, and a
+     * visual indication of the error index within the pattern.
+     *
+     * @return  The full detail message
+     */
+    public String getMessage() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(desc);
+        if (index >= 0) {
+            sb.append(" near index ");
+            sb.append(index);
+        }
+        sb.append(System.lineSeparator());
+        sb.append(pattern);
+        if (index >= 0 && pattern != null && index < pattern.length()) {
+            sb.append(System.lineSeparator());
+            for (int i = 0; i < index; i++) {
+                sb.append((pattern.charAt(i) == '\t') ? '\t' : ' ');
+            }
+            sb.append('^');
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/android-35/java/util/regex/package-info.java b/android-35/java/util/regex/package-info.java
new file mode 100644
index 0000000..3acdb72
--- /dev/null
+++ b/android-35/java/util/regex/package-info.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Classes for matching character sequences against patterns specified
+ * by regular expressions.
+ *
+ * <p> An instance of the {@link java.util.regex.Pattern} class
+ * represents a regular expression that is specified in string form in
+ * a syntax similar to that used by Perl.
+ *
+ * <p> Instances of the {@link java.util.regex.Matcher} class are used
+ * to match character sequences against a given pattern.  Input is
+ * provided to matchers via the {@link java.lang.CharSequence}
+ * interface in order to support matching against characters from a
+ * wide variety of input sources. </p>
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a
+ * method in any class or interface in this package will cause a
+ * {@link java.lang.NullPointerException NullPointerException} to be
+ * thrown.
+ *
+ * <h2>Related Documentation</h2>
+ *
+ * <p> An excellent tutorial and overview of regular expressions is <a
+ * href="http://www.oreilly.com/catalog/regex/"><i>Mastering Regular
+ * Expressions</i>, Jeffrey E. F. Friedl, O'Reilly and Associates,
+ * 1997.</a> </p>
+ *
+ * @since 1.4
+ * @author Mike McCloskey
+ * @author Mark Reinhold
+ */
+package java.util.regex;
diff --git a/android-35/java/util/stream/AbstractPipeline.java b/android-35/java/util/stream/AbstractPipeline.java
new file mode 100644
index 0000000..8040fc1
--- /dev/null
+++ b/android-35/java/util/stream/AbstractPipeline.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for "pipeline" classes, which are the core
+ * implementations of the Stream interface and its primitive specializations.
+ * Manages construction and evaluation of stream pipelines.
+ *
+ * <p>An {@code AbstractPipeline} represents an initial portion of a stream
+ * pipeline, encapsulating a stream source and zero or more intermediate
+ * operations.  The individual {@code AbstractPipeline} objects are often
+ * referred to as <em>stages</em>, where each stage describes either the stream
+ * source or an intermediate operation.
+ *
+ * <p>A concrete intermediate stage is generally built from an
+ * {@code AbstractPipeline}, a shape-specific pipeline class which extends it
+ * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific
+ * concrete class which extends that.  {@code AbstractPipeline} contains most of
+ * the mechanics of evaluating the pipeline, and implements methods that will be
+ * used by the operation; the shape-specific classes add helper methods for
+ * dealing with collection of results into the appropriate shape-specific
+ * containers.
+ *
+ * <p>After chaining a new intermediate operation, or executing a terminal
+ * operation, the stream is considered to be consumed, and no more intermediate
+ * or terminal operations are permitted on this stream instance.
+ *
+ * @implNote
+ * <p>For sequential streams, and parallel streams without
+ * <a href="package-summary.html#StreamOps">stateful intermediate
+ * operations</a>, parallel streams, pipeline evaluation is done in a single
+ * pass that "jams" all the operations together.  For parallel streams with
+ * stateful operations, execution is divided into segments, where each
+ * stateful operations marks the end of a segment, and each segment is
+ * evaluated separately and the result used as the input to the next
+ * segment.  In all cases, the source data is not consumed until a terminal
+ * operation begins.
+ *
+ * @param <E_IN>  type of input elements
+ * @param <E_OUT> type of output elements
+ * @param <S> type of the subclass implementing {@code BaseStream}
+ * @since 1.8
+ * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
+        extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+    private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+    private static final String MSG_CONSUMED = "source already consumed or closed";
+
+    /**
+     * Backlink to the head of the pipeline chain (self if this is the source
+     * stage).
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline sourceStage;
+
+    /**
+     * The "upstream" pipeline, or null if this is the source stage.
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline previousStage;
+
+    /**
+     * The operation flags for the intermediate operation represented by this
+     * pipeline object.
+     */
+    protected final int sourceOrOpFlags;
+
+    /**
+     * The next stage in the pipeline, or null if this is the last stage.
+     * Effectively final at the point of linking to the next pipeline.
+     */
+    @SuppressWarnings("rawtypes")
+    private AbstractPipeline nextStage;
+
+    /**
+     * The number of intermediate operations between this pipeline object
+     * and the stream source if sequential, or the previous stateful if parallel.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int depth;
+
+    /**
+     * The combined source and operation flags for the source and all operations
+     * up to and including the operation represented by this pipeline object.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int combinedFlags;
+
+    /**
+     * The source spliterator. Only valid for the head pipeline.
+     * Before the pipeline is consumed if non-null then {@code sourceSupplier}
+     * must be null. After the pipeline is consumed if non-null then is set to
+     * null.
+     */
+    private Spliterator<?> sourceSpliterator;
+
+    /**
+     * The source supplier. Only valid for the head pipeline. Before the
+     * pipeline is consumed if non-null then {@code sourceSpliterator} must be
+     * null. After the pipeline is consumed if non-null then is set to null.
+     */
+    private Supplier<? extends Spliterator<?>> sourceSupplier;
+
+    /**
+     * True if this pipeline has been linked or consumed
+     */
+    private boolean linkedOrConsumed;
+
+    /**
+     * True if there are any stateful ops in the pipeline; only valid for the
+     * source stage.
+     */
+    private boolean sourceAnyStateful;
+
+    private Runnable sourceCloseAction;
+
+    /**
+     * True if pipeline is parallel, otherwise the pipeline is sequential; only
+     * valid for the source stage.
+     */
+    private boolean parallel;
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel True if the pipeline is parallel
+     */
+    AbstractPipeline(Supplier<? extends Spliterator<?>> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSupplier = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    AbstractPipeline(Spliterator<?> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSpliterator = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for appending an intermediate operation stage onto an
+     * existing pipeline.
+     *
+     * @param previousStage the upstream pipeline stage
+     * @param opFlags the operation flags for the new stage, described in
+     * {@link StreamOpFlag}
+     */
+    AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
+        if (previousStage.linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        previousStage.linkedOrConsumed = true;
+        previousStage.nextStage = this;
+
+        this.previousStage = previousStage;
+        this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
+        this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
+        this.sourceStage = previousStage.sourceStage;
+        if (opIsStateful())
+            sourceStage.sourceAnyStateful = true;
+        this.depth = previousStage.depth + 1;
+    }
+
+
+    // Terminal evaluation methods
+
+    /**
+     * Evaluate the pipeline with a terminal operation to produce a result.
+     *
+     * @param <R> the type of result
+     * @param terminalOp the terminal operation to be applied to the pipeline.
+     * @return the result
+     */
+    final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
+        assert getOutputShape() == terminalOp.inputShape();
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        return isParallel()
+               ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
+               : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
+    }
+
+    /**
+     * Collect the elements output from the pipeline stage.
+     *
+     * @param generator the array generator to be used to create array instances
+     * @return a flat array-backed Node that holds the collected output elements
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        // If the last intermediate operation is stateful then
+        // evaluate directly to avoid an extra collection step
+        if (isParallel() && previousStage != null && opIsStateful()) {
+            // Set the depth of this, last, pipeline stage to zero to slice the
+            // pipeline such that this operation will not be included in the
+            // upstream slice and upstream operations will not be included
+            // in this slice
+            depth = 0;
+            return opEvaluateParallel(previousStage, previousStage.sourceSpliterator(0), generator);
+        }
+        else {
+            return evaluate(sourceSpliterator(0), true, generator);
+        }
+    }
+
+    /**
+     * Gets the source stage spliterator if this pipeline stage is the source
+     * stage.  The pipeline is consumed after this method is called and
+     * returns successfully.
+     *
+     * @return the source stage spliterator
+     * @throws IllegalStateException if this pipeline stage is not the source
+     *         stage.
+     */
+    @SuppressWarnings("unchecked")
+    final Spliterator<E_OUT> sourceStageSpliterator() {
+        if (this != sourceStage)
+            throw new IllegalStateException();
+
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (sourceStage.sourceSpliterator != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+            return s;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+            return s;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+    }
+
+    // BaseStream
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S sequential() {
+        sourceStage.parallel = false;
+        return (S) this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S parallel() {
+        sourceStage.parallel = true;
+        return (S) this;
+    }
+
+    @Override
+    public void close() {
+        linkedOrConsumed = true;
+        sourceSupplier = null;
+        sourceSpliterator = null;
+        if (sourceStage.sourceCloseAction != null) {
+            Runnable closeAction = sourceStage.sourceCloseAction;
+            sourceStage.sourceCloseAction = null;
+            closeAction.run();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public S onClose(Runnable closeHandler) {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        Objects.requireNonNull(closeHandler);
+        Runnable existingHandler = sourceStage.sourceCloseAction;
+        sourceStage.sourceCloseAction =
+                (existingHandler == null)
+                ? closeHandler
+                : Streams.composeWithExceptions(existingHandler, closeHandler);
+        return (S) this;
+    }
+
+    // Primitive specialization use co-variant overrides, hence is not final
+    @Override
+    @SuppressWarnings("unchecked")
+    public Spliterator<E_OUT> spliterator() {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (this == sourceStage) {
+            if (sourceStage.sourceSpliterator != null) {
+                @SuppressWarnings("unchecked")
+                Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSpliterator;
+                sourceStage.sourceSpliterator = null;
+                return s;
+            }
+            else if (sourceStage.sourceSupplier != null) {
+                @SuppressWarnings("unchecked")
+                Supplier<Spliterator<E_OUT>> s = (Supplier<Spliterator<E_OUT>>) sourceStage.sourceSupplier;
+                sourceStage.sourceSupplier = null;
+                return lazySpliterator(s);
+            }
+            else {
+                throw new IllegalStateException(MSG_CONSUMED);
+            }
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator(0), isParallel());
+        }
+    }
+
+    @Override
+    public final boolean isParallel() {
+        return sourceStage.parallel;
+    }
+
+
+    /**
+     * Returns the composition of stream flags of the stream source and all
+     * intermediate operations.
+     *
+     * @return the composition of stream flags of the stream source and all
+     *         intermediate operations
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamFlags() {
+        return StreamOpFlag.toStreamFlags(combinedFlags);
+    }
+
+    /**
+     * Get the source spliterator for this pipeline stage.  For a sequential or
+     * stateless parallel pipeline, this is the source spliterator.  For a
+     * stateful parallel pipeline, this is a spliterator describing the results
+     * of all computations up to and including the most recent stateful
+     * operation.
+     */
+    @SuppressWarnings("unchecked")
+    private Spliterator<?> sourceSpliterator(int terminalFlags) {
+        // Get the source spliterator of the pipeline
+        Spliterator<?> spliterator = null;
+        if (sourceStage.sourceSpliterator != null) {
+            spliterator = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            spliterator = (Spliterator<?>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+
+        if (isParallel() && sourceStage.sourceAnyStateful) {
+            // Adapt the source spliterator, evaluating each stateful op
+            // in the pipeline up to and including this pipeline stage.
+            // The depth and flags of each pipeline stage are adjusted accordingly.
+            int depth = 1;
+            for (@SuppressWarnings("rawtypes") AbstractPipeline u = sourceStage, p = sourceStage.nextStage, e = this;
+                 u != e;
+                 u = p, p = p.nextStage) {
+
+                int thisOpFlags = p.sourceOrOpFlags;
+                if (p.opIsStateful()) {
+                    depth = 0;
+
+                    if (StreamOpFlag.SHORT_CIRCUIT.isKnown(thisOpFlags)) {
+                        // Clear the short circuit flag for next pipeline stage
+                        // This stage encapsulates short-circuiting, the next
+                        // stage may not have any short-circuit operations, and
+                        // if so spliterator.forEachRemaining should be used
+                        // for traversal
+                        thisOpFlags = thisOpFlags & ~StreamOpFlag.IS_SHORT_CIRCUIT;
+                    }
+
+                    spliterator = p.opEvaluateParallelLazy(u, spliterator);
+
+                    // Inject or clear SIZED on the source pipeline stage
+                    // based on the stage's spliterator
+                    thisOpFlags = spliterator.hasCharacteristics(Spliterator.SIZED)
+                            ? (thisOpFlags & ~StreamOpFlag.NOT_SIZED) | StreamOpFlag.IS_SIZED
+                            : (thisOpFlags & ~StreamOpFlag.IS_SIZED) | StreamOpFlag.NOT_SIZED;
+                }
+                p.depth = depth++;
+                p.combinedFlags = StreamOpFlag.combineOpFlags(thisOpFlags, u.combinedFlags);
+            }
+        }
+
+        if (terminalFlags != 0)  {
+            // Apply flags from the terminal operation to last pipeline stage
+            combinedFlags = StreamOpFlag.combineOpFlags(terminalFlags, combinedFlags);
+        }
+
+        return spliterator;
+    }
+
+    // PipelineHelper
+
+    @Override
+    final StreamShape getSourceShape() {
+        @SuppressWarnings("rawtypes")
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        return p.getOutputShape();
+    }
+
+    @Override
+    final <P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator) {
+        int flags = getStreamAndOpFlags();
+        long size = StreamOpFlag.SIZED.isKnown(flags) ? spliterator.getExactSizeIfKnown() : -1;
+        // Currently, we have no stateless SIZE_ADJUSTING intermediate operations,
+        // so we can simply ignore SIZE_ADJUSTING in parallel streams, since adjustments
+        // are already accounted in the input spliterator.
+        //
+        // If we ever have a stateless SIZE_ADJUSTING intermediate operation,
+        // we would need step back until depth == 0, then call exactOutputSize() for
+        // the subsequent stages.
+        if (size != -1 && StreamOpFlag.SIZE_ADJUSTING.isKnown(flags) && !isParallel()) {
+            // Skip the source stage as it's never SIZE_ADJUSTING
+            for (AbstractPipeline<?, ?, ?> stage = sourceStage.nextStage; stage != null; stage = stage.nextStage) {
+                size = stage.exactOutputSize(size);
+            }
+        }
+        return size;
+    }
+
+    /**
+     * Returns the exact output size of the pipeline given the exact size reported by the previous stage.
+     *
+     * @param previousSize the exact size reported by the previous stage
+     * @return the output size of this stage
+     */
+    long exactOutputSize(long previousSize) {
+        return previousSize;
+    }
+
+    @Override
+    final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
+        copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
+        return sink;
+    }
+
+    @Override
+    final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        Objects.requireNonNull(wrappedSink);
+
+        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
+            wrappedSink.begin(spliterator.getExactSizeIfKnown());
+            spliterator.forEachRemaining(wrappedSink);
+            wrappedSink.end();
+        }
+        else {
+            copyIntoWithCancel(wrappedSink, spliterator);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> boolean copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        @SuppressWarnings({"rawtypes","unchecked"})
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+
+        wrappedSink.begin(spliterator.getExactSizeIfKnown());
+        boolean cancelled = p.forEachWithCancel(spliterator, wrappedSink);
+        wrappedSink.end();
+        return cancelled;
+    }
+
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamAndOpFlags() {
+        return combinedFlags;
+    }
+
+    final boolean isOrdered() {
+        return StreamOpFlag.ORDERED.isKnown(combinedFlags);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
+        Objects.requireNonNull(sink);
+
+        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
+            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
+        }
+        return (Sink<P_IN>) sink;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> Spliterator<E_OUT> wrapSpliterator(Spliterator<P_IN> sourceSpliterator) {
+        if (depth == 0) {
+            return (Spliterator<E_OUT>) sourceSpliterator;
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator, isParallel());
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Node<E_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                      boolean flatten,
+                                      IntFunction<E_OUT[]> generator) {
+        if (isParallel()) {
+            // @@@ Optimize if op of this pipeline stage is a stateful op
+            return evaluateToNode(this, spliterator, flatten, generator);
+        }
+        else {
+            Node.Builder<E_OUT> nb = makeNodeBuilder(
+                    exactOutputSizeIfKnown(spliterator), generator);
+            return wrapAndCopyInto(nb, spliterator).build();
+        }
+    }
+
+
+    // Shape-specific abstract methods, implemented by XxxPipeline classes
+
+    /**
+     * Get the output shape of the pipeline.  If the pipeline is the head,
+     * then it's output shape corresponds to the shape of the source.
+     * Otherwise, it's output shape corresponds to the output shape of the
+     * associated operation.
+     *
+     * @return the output shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract StreamShape getOutputShape();
+
+    /**
+     * Collect elements output from a pipeline into a Node that holds elements
+     * of this shape.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source spliterator
+     * @param flattenTree true if the returned node should be flattened
+     * @param generator the array generator
+     * @return a Node holding the output of the pipeline
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Node<E_OUT> evaluateToNode(PipelineHelper<E_OUT> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      boolean flattenTree,
+                                                      IntFunction<E_OUT[]> generator);
+
+    /**
+     * Create a spliterator that wraps a source spliterator, compatible with
+     * this stream shape, and operations associated with a {@link
+     * PipelineHelper}.
+     *
+     * @param ph the pipeline helper describing the pipeline stages
+     * @param supplier the supplier of a spliterator
+     * @return a wrapping spliterator compatible with this shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Spliterator<E_OUT> wrap(PipelineHelper<E_OUT> ph,
+                                                   Supplier<Spliterator<P_IN>> supplier,
+                                                   boolean isParallel);
+
+    /**
+     * Create a lazy spliterator that wraps and obtains the supplied the
+     * spliterator when a method is invoked on the lazy spliterator.
+     * @param supplier the supplier of a spliterator
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Spliterator<E_OUT> lazySpliterator(Supplier<? extends Spliterator<E_OUT>> supplier);
+
+    /**
+     * Traverse the elements of a spliterator compatible with this stream shape,
+     * pushing those elements into a sink.   If the sink requests cancellation,
+     * no further elements will be pulled or pushed.
+     *
+     * @param spliterator the spliterator to pull elements from
+     * @param sink the sink to push elements to
+     * @return true if the cancellation was requested
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract boolean forEachWithCancel(Spliterator<E_OUT> spliterator, Sink<E_OUT> sink);
+
+    /**
+     * Make a node builder compatible with this stream shape.
+     *
+     * @param exactSizeIfKnown if {@literal >=0}, then a node builder will be
+     * created that has a fixed capacity of at most sizeIfKnown elements. If
+     * {@literal < 0}, then the node builder has an unfixed capacity. A fixed
+     * capacity node builder will throw exceptions if an element is added after
+     * builder has reached capacity, or is built before the builder has reached
+     * capacity.
+     *
+     * @param generator the array generator to be used to create instances of a
+     * T[] array. For implementations supporting primitive nodes, this parameter
+     * may be ignored.
+     * @return a node builder
+     */
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public abstract Node.Builder<E_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                        IntFunction<E_OUT[]> generator);
+
+
+    // Op-specific abstract methods, implemented by the operation class
+
+    /**
+     * Returns whether this operation is stateful or not.  If it is stateful,
+     * then the method
+     * {@link #opEvaluateParallel(PipelineHelper, java.util.Spliterator, java.util.function.IntFunction)}
+     * must be overridden.
+     *
+     * @return {@code true} if this operation is stateful
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract boolean opIsStateful();
+
+    /**
+     * Accepts a {@code Sink} which will receive the results of this operation,
+     * and return a {@code Sink} which accepts elements of the input type of
+     * this operation and which performs the operation, passing the results to
+     * the provided {@code Sink}.
+     *
+     * @apiNote
+     * The implementation may use the {@code flags} parameter to optimize the
+     * sink wrapping.  For example, if the input is already {@code DISTINCT},
+     * the implementation for the {@code Stream#distinct()} method could just
+     * return the sink it was passed.
+     *
+     * @param flags The combined stream and operation flags up to, but not
+     *        including, this operation
+     * @param sink sink to which elements should be sent after processing
+     * @return a sink which accepts elements, perform the operation upon
+     *         each element, and passes the results (if any) to the provided
+     *         {@code Sink}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink);
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper} which describes the upstream intermediate
+     * operations.  Only called on stateful operations.  If {@link
+     * #opIsStateful()} returns true then implementations must override the
+     * default implementation.
+     *
+     * @implSpec The default implementation always throw
+     * {@code UnsupportedOperationException}.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source {@code Spliterator}
+     * @param generator the array generator
+     * @return a {@code Node} describing the result of the evaluation
+     */
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                          Spliterator<P_IN> spliterator,
+                                          IntFunction<E_OUT[]> generator) {
+        throw new UnsupportedOperationException("Parallel evaluation is not supported");
+    }
+
+    /**
+     * Returns a {@code Spliterator} describing a parallel evaluation of the
+     * operation, using the specified {@code PipelineHelper} which describes the
+     * upstream intermediate operations.  Only called on stateful operations.
+     * It is not necessary (though acceptable) to do a full computation of the
+     * result here; it is preferable, if possible, to describe the result via a
+     * lazily evaluated spliterator.
+     *
+     * @implSpec The default implementation behaves as if:
+     * <pre>{@code
+     *     return evaluateParallel(helper, i -> (E_OUT[]) new
+     * Object[i]).spliterator();
+     * }</pre>
+     * and is suitable for implementations that cannot do better than a full
+     * synchronous evaluation.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source {@code Spliterator}
+     * @return a {@code Spliterator} describing the result of the evaluation
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Spliterator<E_OUT> opEvaluateParallelLazy(PipelineHelper<E_OUT> helper,
+                                                     Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E_OUT[]) new Object[i]).spliterator();
+    }
+}
diff --git a/android-35/java/util/stream/AbstractShortCircuitTask.java b/android-35/java/util/stream/AbstractShortCircuitTask.java
new file mode 100644
index 0000000..d59fcfa
--- /dev/null
+++ b/android-35/java/util/stream/AbstractShortCircuitTask.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Abstract class for fork-join tasks used to implement short-circuiting
+ * stream ops, which can produce a result without processing all elements of the
+ * stream.
+ *
+ * @param <P_IN> type of input elements to the pipeline
+ * @param <P_OUT> type of output elements from the pipeline
+ * @param <R> type of intermediate result, may be different from operation
+ *        result type
+ * @param <K> type of child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractShortCircuitTask<P_IN, P_OUT, R,
+                                        K extends AbstractShortCircuitTask<P_IN, P_OUT, R, K>>
+        extends AbstractTask<P_IN, P_OUT, R, K> {
+    /**
+     * The result for this computation; this is shared among all tasks and set
+     * exactly once
+     */
+    protected final AtomicReference<R> sharedResult;
+
+    /**
+     * Indicates whether this task has been canceled.  Tasks may cancel other
+     * tasks in the computation under various conditions, such as in a
+     * find-first operation, a task that finds a value will cancel all tasks
+     * that are later in the encounter order.
+     */
+    protected volatile boolean canceled;
+
+    /**
+     * Constructor for root tasks.
+     *
+     * @param helper the {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator the {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractShortCircuitTask(PipelineHelper<P_OUT> helper,
+                                       Spliterator<P_IN> spliterator) {
+        super(helper, spliterator);
+        sharedResult = new AtomicReference<>();
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent parent task in the computation tree
+     * @param spliterator the {@code Spliterator} for the portion of the
+     *                    computation tree described by this task
+     */
+    protected AbstractShortCircuitTask(K parent,
+                                       Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+        sharedResult = parent.sharedResult;
+    }
+
+    /**
+     * Returns the value indicating the computation completed with no task
+     * finding a short-circuitable result.  For example, for a "find" operation,
+     * this might be null or an empty {@code Optional}.
+     *
+     * @return the result to return when no task finds a result
+     */
+    protected abstract R getEmptyResult();
+
+    /**
+     * Overrides AbstractTask version to include checks for early
+     * exits while splitting or computing.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls;
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        AtomicReference<R> sr = sharedResult;
+        R result;
+        while ((result = sr.get()) == null) {
+            if (task.taskCanceled()) {
+                result = task.getEmptyResult();
+                break;
+            }
+            if (sizeEstimate <= sizeThreshold || (ls = rs.trySplit()) == null) {
+                result = task.doLeaf();
+                break;
+            }
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(result);
+        task.tryComplete();
+    }
+
+
+    /**
+     * Declares that a globally valid result has been found.  If another task has
+     * not already found the answer, the result is installed in
+     * {@code sharedResult}.  The {@code compute()} method will check
+     * {@code sharedResult} before proceeding with computation, so this causes
+     * the computation to terminate early.
+     *
+     * @param result the result found
+     */
+    protected void shortCircuit(R result) {
+        if (result != null)
+            sharedResult.compareAndSet(null, result);
+    }
+
+    /**
+     * Sets a local result for this task.  If this task is the root, set the
+     * shared result instead (if not already set).
+     *
+     * @param localResult The result to set for this task
+     */
+    @Override
+    protected void setLocalResult(R localResult) {
+        if (isRoot()) {
+            if (localResult != null)
+                sharedResult.compareAndSet(null, localResult);
+        }
+        else
+            super.setLocalResult(localResult);
+    }
+
+    /**
+     * Retrieves the local result for this task
+     */
+    @Override
+    public R getRawResult() {
+        return getLocalResult();
+    }
+
+    /**
+     * Retrieves the local result for this task.  If this task is the root,
+     * retrieves the shared result instead.
+     */
+    @Override
+    public R getLocalResult() {
+        if (isRoot()) {
+            R answer = sharedResult.get();
+            return (answer == null) ? getEmptyResult() : answer;
+        }
+        else
+            return super.getLocalResult();
+    }
+
+    /**
+     * Mark this task as canceled
+     */
+    protected void cancel() {
+        canceled = true;
+    }
+
+    /**
+     * Queries whether this task is canceled.  A task is considered canceled if
+     * it or any of its parents have been canceled.
+     *
+     * @return {@code true} if this task or any parent is canceled.
+     */
+    protected boolean taskCanceled() {
+        boolean cancel = canceled;
+        if (!cancel) {
+            for (K parent = getParent(); !cancel && parent != null; parent = parent.getParent())
+                cancel = parent.canceled;
+        }
+
+        return cancel;
+    }
+
+    /**
+     * Cancels all tasks which succeed this one in the encounter order.  This
+     * includes canceling all the current task's right sibling, as well as the
+     * later right siblings of all its parents.
+     */
+    protected void cancelLaterNodes() {
+        // Go up the tree, cancel right siblings of this node and all parents
+        for (@SuppressWarnings("unchecked") K parent = getParent(), node = (K) this;
+             parent != null;
+             node = parent, parent = parent.getParent()) {
+            // If node is a left child of parent, then has a right sibling
+            if (parent.leftChild == node) {
+                K rightSibling = parent.rightChild;
+                if (!rightSibling.canceled)
+                    rightSibling.cancel();
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/stream/AbstractSpinedBuffer.java b/android-35/java/util/stream/AbstractSpinedBuffer.java
new file mode 100644
index 0000000..46fdf4d
--- /dev/null
+++ b/android-35/java/util/stream/AbstractSpinedBuffer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Base class for a data structure for gathering elements into a buffer and then
+ * iterating them. Maintains an array of increasingly sized arrays, so there is
+ * no copying cost associated with growing the data structure.
+ * @since 1.8
+ */
+abstract class AbstractSpinedBuffer {
+    /**
+     * Minimum power-of-two for the first chunk.
+     */
+    public static final int MIN_CHUNK_POWER = 4;
+
+    /**
+     * Minimum size for the first chunk.
+     */
+    public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER;
+
+    /**
+     * Max power-of-two for chunks.
+     */
+    public static final int MAX_CHUNK_POWER = 30;
+
+    /**
+     * Minimum array size for array-of-chunks.
+     */
+    public static final int MIN_SPINE_SIZE = 8;
+
+
+    /**
+     * log2 of the size of the first chunk.
+     */
+    protected final int initialChunkPower;
+
+    /**
+     * Index of the *next* element to write; may point into, or just outside of,
+     * the current chunk.
+     */
+    protected int elementIndex;
+
+    /**
+     * Index of the *current* chunk in the spine array, if the spine array is
+     * non-null.
+     */
+    protected int spineIndex;
+
+    /**
+     * Count of elements in all prior chunks.
+     */
+    protected long[] priorElementCount;
+
+    /**
+     * Construct with an initial capacity of 16.
+     */
+    protected AbstractSpinedBuffer() {
+        this.initialChunkPower = MIN_CHUNK_POWER;
+    }
+
+    /**
+     * Construct with a specified initial capacity.
+     *
+     * @param initialCapacity The minimum expected number of elements
+     */
+    protected AbstractSpinedBuffer(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
+
+        this.initialChunkPower = Math.max(MIN_CHUNK_POWER,
+                                          Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1));
+    }
+
+    /**
+     * Is the buffer currently empty?
+     */
+    public boolean isEmpty() {
+        return (spineIndex == 0) && (elementIndex == 0);
+    }
+
+    /**
+     * How many elements are currently in the buffer?
+     */
+    public long count() {
+        return (spineIndex == 0)
+               ? elementIndex
+               : priorElementCount[spineIndex] + elementIndex;
+    }
+
+    /**
+     * How big should the nth chunk be?
+     */
+    protected int chunkSize(int n) {
+        int power = (n == 0 || n == 1)
+                    ? initialChunkPower
+                    : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER);
+        return 1 << power;
+    }
+
+    /**
+     * Remove all data from the buffer
+     */
+    public abstract void clear();
+}
diff --git a/android-35/java/util/stream/AbstractTask.java b/android-35/java/util/stream/AbstractTask.java
new file mode 100644
index 0000000..44c2656
--- /dev/null
+++ b/android-35/java/util/stream/AbstractTask.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinWorkerThread;
+
+/**
+ * Abstract base class for most fork-join tasks used to implement stream ops.
+ * Manages splitting logic, tracking of child tasks, and intermediate results.
+ * Each task is associated with a {@link Spliterator} that describes the portion
+ * of the input associated with the subtree rooted at this task.
+ * Tasks may be leaf nodes (which will traverse the elements of
+ * the {@code Spliterator}) or internal nodes (which split the
+ * {@code Spliterator} into multiple child tasks).
+ *
+ * @implNote
+ * <p>This class is based on {@link CountedCompleter}, a form of fork-join task
+ * where each task has a semaphore-like count of uncompleted children, and the
+ * task is implicitly completed and notified when its last child completes.
+ * Internal node tasks will likely override the {@code onCompletion} method from
+ * {@code CountedCompleter} to merge the results from child tasks into the
+ * current task's result.
+ *
+ * <p>Splitting and setting up the child task links is done by {@code compute()}
+ * for internal nodes.  At {@code compute()} time for leaf nodes, it is
+ * guaranteed that the parent's child-related fields (including sibling links
+ * for the parent's children) will be set up for all children.
+ *
+ * <p>For example, a task that performs a reduce would override {@code doLeaf()}
+ * to perform a reduction on that leaf node's chunk using the
+ * {@code Spliterator}, and override {@code onCompletion()} to merge the results
+ * of the child tasks for internal nodes:
+ *
+ * <pre>{@code
+ *     protected S doLeaf() {
+ *         spliterator.forEach(...);
+ *         return localReductionResult;
+ *     }
+ *
+ *     public void onCompletion(CountedCompleter caller) {
+ *         if (!isLeaf()) {
+ *             ReduceTask<P_IN, P_OUT, T, R> child = children;
+ *             R result = child.getLocalResult();
+ *             child = child.nextSibling;
+ *             for (; child != null; child = child.nextSibling)
+ *                 result = combine(result, child.getLocalResult());
+ *             setLocalResult(result);
+ *         }
+ *     }
+ * }</pre>
+ *
+ * <p>Serialization is not supported as there is no intention to serialize
+ * tasks managed by stream ops.
+ *
+ * @param <P_IN> Type of elements input to the pipeline
+ * @param <P_OUT> Type of elements output from the pipeline
+ * @param <R> Type of intermediate result, which may be different from operation
+ *        result type
+ * @param <K> Type of parent, child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractTask<P_IN, P_OUT, R,
+                            K extends AbstractTask<P_IN, P_OUT, R, K>>
+        extends CountedCompleter<R> {
+
+    private static final int LEAF_TARGET = ForkJoinPool.getCommonPoolParallelism() << 2;
+
+    /** The pipeline helper, common to all tasks in a computation */
+    protected final PipelineHelper<P_OUT> helper;
+
+    /**
+     * The spliterator for the portion of the input associated with the subtree
+     * rooted at this task
+     */
+    protected Spliterator<P_IN> spliterator;
+
+    /** Target leaf size, common to all tasks in a computation */
+    protected long targetSize; // may be lazily initialized
+
+    /**
+     * The left child.
+     * null if no children
+     * if non-null rightChild is non-null
+     */
+    protected K leftChild;
+
+    /**
+     * The right child.
+     * null if no children
+     * if non-null leftChild is non-null
+     */
+    protected K rightChild;
+
+    /** The result of this node, if completed */
+    private R localResult;
+
+    /**
+     * Constructor for root nodes.
+     *
+     * @param helper The {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator The {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractTask(PipelineHelper<P_OUT> helper,
+                           Spliterator<P_IN> spliterator) {
+        super(null);
+        this.helper = helper;
+        this.spliterator = spliterator;
+        this.targetSize = 0L;
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent this node's parent task
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     */
+    protected AbstractTask(K parent,
+                           Spliterator<P_IN> spliterator) {
+        super(parent);
+        this.spliterator = spliterator;
+        this.helper = parent.helper;
+        this.targetSize = parent.targetSize;
+    }
+
+    /**
+     * Default target of leaf tasks for parallel decomposition.
+     * To allow load balancing, we over-partition, currently to approximately
+     * four tasks per processor, which enables others to help out
+     * if leaf tasks are uneven or some processors are otherwise busy.
+     */
+    public static int getLeafTarget() {
+        Thread t = Thread.currentThread();
+        if (t instanceof ForkJoinWorkerThread) {
+            return ((ForkJoinWorkerThread) t).getPool().getParallelism() << 2;
+        }
+        else {
+            return LEAF_TARGET;
+        }
+    }
+
+    /**
+     * Constructs a new node of type T whose parent is the receiver; must call
+     * the AbstractTask(T, Spliterator) constructor with the receiver and the
+     * provided Spliterator.
+     *
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     * @return newly constructed child node
+     */
+    protected abstract K makeChild(Spliterator<P_IN> spliterator);
+
+    /**
+     * Computes the result associated with a leaf node.  Will be called by
+     * {@code compute()} and the result passed to @{code setLocalResult()}
+     *
+     * @return the computed result of a leaf node
+     */
+    protected abstract R doLeaf();
+
+    /**
+     * Returns a suggested target leaf size based on the initial size estimate.
+     *
+     * @return suggested target leaf size
+     */
+    public static long suggestTargetSize(long sizeEstimate) {
+        long est = sizeEstimate / getLeafTarget();
+        return est > 0L ? est : 1L;
+    }
+
+    /**
+     * Returns the targetSize, initializing it via the supplied
+     * size estimate if not already initialized.
+     */
+    protected final long getTargetSize(long sizeEstimate) {
+        long s;
+        return ((s = targetSize) != 0 ? s :
+                (targetSize = suggestTargetSize(sizeEstimate)));
+    }
+
+    /**
+     * Returns the local result, if any. Subclasses should use
+     * {@link #setLocalResult(Object)} and {@link #getLocalResult()} to manage
+     * results.  This returns the local result so that calls from within the
+     * fork-join framework will return the correct result.
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    @Override
+    public R getRawResult() {
+        return localResult;
+    }
+
+    /**
+     * Does nothing; instead, subclasses should use
+     * {@link #setLocalResult(Object)}} to manage results.
+     *
+     * @param result must be null, or an exception is thrown (this is a safety
+     *        tripwire to detect when {@code setRawResult()} is being used
+     *        instead of {@code setLocalResult()}
+     */
+    @Override
+    protected void setRawResult(R result) {
+        if (result != null)
+            throw new IllegalStateException();
+    }
+
+    /**
+     * Retrieves a result previously stored with {@link #setLocalResult}
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    protected R getLocalResult() {
+        return localResult;
+    }
+
+    /**
+     * Associates the result with the task, can be retrieved with
+     * {@link #getLocalResult}
+     *
+     * @param localResult local result for this node
+     */
+    protected void setLocalResult(R localResult) {
+        this.localResult = localResult;
+    }
+
+    /**
+     * Indicates whether this task is a leaf node.  (Only valid after
+     * {@link #compute} has been called on this node).  If the node is not a
+     * leaf node, then children will be non-null and numChildren will be
+     * positive.
+     *
+     * @return {@code true} if this task is a leaf node
+     */
+    protected boolean isLeaf() {
+        return leftChild == null;
+    }
+
+    /**
+     * Indicates whether this task is the root node
+     *
+     * @return {@code true} if this task is the root node.
+     */
+    protected boolean isRoot() {
+        return getParent() == null;
+    }
+
+    /**
+     * Returns the parent of this task, or null if this task is the root
+     *
+     * @return the parent of this task, or null if this task is the root
+     */
+    @SuppressWarnings("unchecked")
+    protected K getParent() {
+        return (K) getCompleter();
+    }
+
+    /**
+     * Decides whether or not to split a task further or compute it
+     * directly. If computing directly, calls {@code doLeaf} and pass
+     * the result to {@code setRawResult}. Otherwise splits off
+     * subtasks, forking one and continuing as the other.
+     *
+     * <p> The method is structured to conserve resources across a
+     * range of uses.  The loop continues with one of the child tasks
+     * when split, to avoid deep recursion. To cope with spliterators
+     * that may be systematically biased toward left-heavy or
+     * right-heavy splits, we alternate which child is forked versus
+     * continued in the loop.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls; // right, left spliterators
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        while (sizeEstimate > sizeThreshold && (ls = rs.trySplit()) != null) {
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(task.doLeaf());
+        task.tryComplete();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote
+     * Clears spliterator and children fields.  Overriders MUST call
+     * {@code super.onCompletion} as the last thing they do if they want these
+     * cleared.
+     */
+    @Override
+    public void onCompletion(CountedCompleter<?> caller) {
+        spliterator = null;
+        leftChild = rightChild = null;
+    }
+
+    /**
+     * Returns whether this node is a "leftmost" node -- whether the path from
+     * the root to this node involves only traversing leftmost child links.  For
+     * a leaf node, this means it is the first leaf node in the encounter order.
+     *
+     * @return {@code true} if this node is a "leftmost" node
+     */
+    protected boolean isLeftmostNode() {
+        @SuppressWarnings("unchecked")
+        K node = (K) this;
+        while (node != null) {
+            K parent = node.getParent();
+            if (parent != null && parent.leftChild != node)
+                return false;
+            node = parent;
+        }
+        return true;
+    }
+}
diff --git a/android-35/java/util/stream/BaseStream.java b/android-35/java/util/stream/BaseStream.java
new file mode 100644
index 0000000..0328b25
--- /dev/null
+++ b/android-35/java/util/stream/BaseStream.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
+
+/**
+ * Base interface for streams, which are sequences of elements supporting
+ * sequential and parallel aggregate operations.  The following example
+ * illustrates an aggregate operation using the stream types {@link Stream}
+ * and {@link IntStream}, computing the sum of the weights of the red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism, which governs the behavior of all stream types.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of the stream implementing {@code BaseStream}
+ * @since 1.8
+ * @see Stream
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface BaseStream<T, S extends BaseStream<T, S>>
+        extends AutoCloseable {
+    /**
+     * Returns an iterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the element iterator for this stream
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Returns a spliterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>
+     * The returned spliterator should report the set of characteristics derived
+     * from the stream pipeline (namely the characteristics derived from the
+     * stream source spliterator and the intermediate operations).
+     * Implementations may report a sub-set of those characteristics.  For
+     * example, it may be too expensive to compute the entire set for some or
+     * all possible stream pipelines.
+     *
+     * @return the element spliterator for this stream
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Returns whether this stream, if a terminal operation were to be executed,
+     * would execute in parallel.  Calling this method after invoking an
+     * terminal stream operation method may yield unpredictable results.
+     *
+     * @return {@code true} if this stream would execute in parallel if executed
+     */
+    boolean isParallel();
+
+    /**
+     * Returns an equivalent stream that is sequential.  May return
+     * itself, either because the stream was already sequential, or because
+     * the underlying stream state was modified to be sequential.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a sequential stream
+     */
+    S sequential();
+
+    /**
+     * Returns an equivalent stream that is parallel.  May return
+     * itself, either because the stream was already parallel, or because
+     * the underlying stream state was modified to be parallel.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a parallel stream
+     */
+    S parallel();
+
+    /**
+     * Returns an equivalent stream that is
+     * <a href="package-summary.html#Ordering">unordered</a>.  May return
+     * itself, either because the stream was already unordered, or because
+     * the underlying stream state was modified to be unordered.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return an unordered stream
+     */
+    S unordered();
+
+    /**
+     * Returns an equivalent stream with an additional close handler.  Close
+     * handlers are run when the {@link #close()} method
+     * is called on the stream, and are executed in the order they were
+     * added.  All close handlers are run, even if earlier close handlers throw
+     * exceptions.  If any close handler throws an exception, the first
+     * exception thrown will be relayed to the caller of {@code close()}, with
+     * any remaining exceptions added to that exception as suppressed exceptions
+     * (unless one of the remaining exceptions is the same exception as the
+     * first exception, since an exception cannot suppress itself.)  May
+     * return itself.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param closeHandler A task to execute when the stream is closed
+     * @return a stream with a handler that is run if the stream is closed
+     */
+    S onClose(Runnable closeHandler);
+
+    /**
+     * Closes this stream, causing all close handlers for this stream pipeline
+     * to be called.
+     *
+     * @see AutoCloseable#close()
+     */
+    @Override
+    void close();
+}
diff --git a/android-35/java/util/stream/Collector.java b/android-35/java/util/stream/Collector.java
new file mode 100644
index 0000000..9ef6567
--- /dev/null
+++ b/android-35/java/util/stream/Collector.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+// A compilation test for the code snippets in this class-level javadoc can be found at:
+// test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorExample.java
+// The test needs to be updated if the examples in this javadoc change or new examples are added.
+
+/**
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
+ * the accumulated result into a final representation after all input elements
+ * have been processed.  Reduction operations can be performed either sequentially
+ * or in parallel.
+ *
+ * <p>Examples of mutable reduction operations include:
+ * accumulating elements into a {@code Collection}; concatenating
+ * strings using a {@code StringBuilder}; computing summary information about
+ * elements such as sum, min, max, or average; computing "pivot table" summaries
+ * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
+ *
+ * <p>A {@code Collector} is specified by four functions that work together to
+ * accumulate entries into a mutable result container, and optionally perform
+ * a final transform on the result.  They are: <ul>
+ *     <li>creation of a new result container ({@link #supplier()})</li>
+ *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ *     <li>combining two result containers into one ({@link #combiner()})</li>
+ *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
+ *
+ * <p>Collectors also have a set of characteristics, such as
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element.  A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result.  That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order.  (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
+ *
+ * <p>Libraries that implement reduction based on {@code Collector}, such as
+ * {@link Stream#collect(Collector)}, must adhere to the following constraints:
+ * <ul>
+ *     <li>The first argument passed to the accumulator function, both
+ *     arguments passed to the combiner function, and the argument passed to the
+ *     finisher function must be the result of a previous invocation of the
+ *     result supplier, accumulator, or combiner functions.</li>
+ *     <li>The implementation should not do anything with the result of any of
+ *     the result supplier, accumulator, or combiner functions other than to
+ *     pass them again to the accumulator, combiner, or finisher functions,
+ *     or return them to the caller of the reduction operation.</li>
+ *     <li>If a result is passed to the combiner or finisher
+ *     function, and the same object is not returned from that function, it is
+ *     never used again.</li>
+ *     <li>Once a result is passed to the combiner or finisher function, it
+ *     is never passed to the accumulator function again.</li>
+ *     <li>For non-concurrent collectors, any result returned from the result
+ *     supplier, accumulator, or combiner functions must be serially
+ *     thread-confined.  This enables collection to occur in parallel without
+ *     the {@code Collector} needing to implement any additional synchronization.
+ *     The reduction implementation must manage that the input is properly
+ *     partitioned, that partitions are processed in isolation, and combining
+ *     happens only after accumulation is complete.</li>
+ *     <li>For concurrent collectors, an implementation is free to (but not
+ *     required to) implement reduction concurrently.  A concurrent reduction
+ *     is one where the accumulator function is called concurrently from
+ *     multiple threads, using the same concurrently-modifiable result container,
+ *     rather than keeping the result isolated during accumulation.
+ *     A concurrent reduction should only be applied if the collector has the
+ *     {@link Characteristics#UNORDERED} characteristics or if the
+ *     originating data is unordered.</li>
+ * </ul>
+ *
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors.  For example, you could create a collector
+ * that accumulates widgets into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ *         Collector.of(TreeSet::new, TreeSet::add,
+ *                      (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
+ * @apiNote
+ * Performing a reduction operation with a {@code Collector} should produce a
+ * result equivalent to:
+ * <pre>{@code
+ *     A container = collector.supplier().get();
+ *     for (T t : data)
+ *         collector.accumulator().accept(container, t);
+ *     return collector.finisher().apply(container);
+ * }</pre>
+ *
+ * <p>However, the library is free to partition the input, perform the reduction
+ * on the partitions, and then use the combiner function to combine the partial
+ * results to achieve a parallel reduction.  (Depending on the specific reduction
+ * operation, this may perform better or worse, depending on the relative cost
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector.  For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * }</pre>
+ *
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * }</pre>
+ *
+ * @see Stream#collect(Collector)
+ * @see Collectors
+ *
+ * @param <T> the type of input elements to the reduction operation
+ * @param <A> the mutable accumulation type of the reduction operation (often
+ *            hidden as an implementation detail)
+ * @param <R> the result type of the reduction operation
+ * @since 1.8
+ */
+public interface Collector<T, A, R> {
+    /**
+     * A function that creates and returns a new mutable result container.
+     *
+     * @return a function which returns a new, mutable result container
+     */
+    Supplier<A> supplier();
+
+    /**
+     * A function that folds a value into a mutable result container.
+     *
+     * @return a function which folds a value into a mutable result container
+     */
+    BiConsumer<A, T> accumulator();
+
+    /**
+     * A function that accepts two partial results and merges them.  The
+     * combiner function may fold state from one argument into the other and
+     * return that, or may return a new result container.
+     *
+     * @return a function which combines two partial results into a combined
+     * result
+     */
+    BinaryOperator<A> combiner();
+
+    /**
+     * Perform the final transformation from the intermediate accumulation type
+     * {@code A} to the final result type {@code R}.
+     *
+     * <p>If the characteristic {@code IDENTITY_FINISH} is
+     * set, this function may be presumed to be an identity transform with an
+     * unchecked cast from {@code A} to {@code R}.
+     *
+     * @return a function which transforms the intermediate result to the final
+     * result
+     */
+    Function<A, R> finisher();
+
+    /**
+     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
+     * the characteristics of this Collector.  This set should be immutable.
+     *
+     * @return an immutable set of collector characteristics
+     */
+    Set<Characteristics> characteristics();
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, and {@code combiner} functions.  The resulting
+     * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH}
+     * characteristic.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <R> The type of intermediate accumulation result, and final result,
+     *           for the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
+                                              BiConsumer<R, T> accumulator,
+                                              BinaryOperator<R> combiner,
+                                              Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = (characteristics.length == 0)
+                                  ? Collectors.CH_ID
+                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
+                                                                           characteristics));
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
+    }
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, {@code combiner}, and {@code finisher} functions.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param finisher The finisher function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <A> The intermediate accumulation type of the new collector
+     * @param <R> The final result type of the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
+                                                 BiConsumer<A, T> accumulator,
+                                                 BinaryOperator<A> combiner,
+                                                 Function<A, R> finisher,
+                                                 Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(finisher);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = Collectors.CH_NOID;
+        if (characteristics.length > 0) {
+            cs = EnumSet.noneOf(Characteristics.class);
+            Collections.addAll(cs, characteristics);
+            cs = Collections.unmodifiableSet(cs);
+        }
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
+    }
+
+    /**
+     * Characteristics indicating properties of a {@code Collector}, which can
+     * be used to optimize reduction implementations.
+     */
+    enum Characteristics {
+        /**
+         * Indicates that this collector is <em>concurrent</em>, meaning that
+         * the result container can support the accumulator function being
+         * called concurrently with the same result container from multiple
+         * threads.
+         *
+         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
+         * then it should only be evaluated concurrently if applied to an
+         * unordered data source.
+         */
+        CONCURRENT,
+
+        /**
+         * Indicates that the collection operation does not commit to preserving
+         * the encounter order of input elements.  (This might be true if the
+         * result container has no intrinsic order, such as a {@link Set}.)
+         */
+        UNORDERED,
+
+        /**
+         * Indicates that the finisher function is the identity function and
+         * can be elided.  If set, it must be the case that an unchecked cast
+         * from A to R will succeed.
+         */
+        IDENTITY_FINISH
+    }
+}
diff --git a/android-35/java/util/stream/Collectors.java b/android-35/java/util/stream/Collectors.java
new file mode 100644
index 0000000..8956823
--- /dev/null
+++ b/android-35/java/util/stream/Collectors.java
@@ -0,0 +1,2030 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.DoubleSummaryStatistics;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LongSummaryStatistics;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * Implementations of {@link Collector} that implement various useful reduction
+ * operations, such as accumulating elements into collections, summarizing
+ * elements according to various criteria, etc.
+ *
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
+ *
+ * <pre>{@code
+ * // Accumulate names into a List
+ * List<String> list = people.stream()
+ *   .map(Person::getName)
+ *   .collect(Collectors.toList());
+ *
+ * // Accumulate names into a TreeSet
+ * Set<String> set = people.stream()
+ *   .map(Person::getName)
+ *   .collect(Collectors.toCollection(TreeSet::new));
+ *
+ * // Convert elements to strings and concatenate them, separated by commas
+ * String joined = things.stream()
+ *   .map(Object::toString)
+ *   .collect(Collectors.joining(", "));
+ *
+ * // Compute sum of salaries of employee
+ * int total = employees.stream()
+ *   .collect(Collectors.summingInt(Employee::getSalary));
+ *
+ * // Group employees by department
+ * Map<Department, List<Employee>> byDept = employees.stream()
+ *   .collect(Collectors.groupingBy(Employee::getDepartment));
+ *
+ * // Compute sum of salaries by department
+ * Map<Department, Integer> totalByDept = employees.stream()
+ *   .collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                  Collectors.summingInt(Employee::getSalary)));
+ *
+ * // Partition students into passing and failing
+ * Map<Boolean, List<Student>> passingFailing = students.stream()
+ *   .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
+ *
+ * }</pre>
+ *
+ * @since 1.8
+ */
+public final class Collectors {
+
+    static final Set<Collector.Characteristics> CH_CONCURRENT_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED));
+    static final Set<Collector.Characteristics> CH_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_UNORDERED_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
+    static final Set<Collector.Characteristics> CH_UNORDERED_NOID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED));
+
+    private Collectors() { }
+
+    /**
+     * Construct an {@code IllegalStateException} with appropriate message.
+     *
+     * @param k the duplicate key
+     * @param u 1st value to be accumulated/merged
+     * @param v 2nd value to be accumulated/merged
+     */
+    private static IllegalStateException duplicateKeyException(
+            Object k, Object u, Object v) {
+        return new IllegalStateException(String.format(
+            "Duplicate key %s (attempted merging values %s and %s)",
+            k, u, v));
+    }
+
+    /**
+     * {@code BinaryOperator<Map>} that merges the contents of its right
+     * argument into its left argument, throwing {@code IllegalStateException}
+     * if duplicate keys are encountered.
+     *
+     * @param <K> type of the map keys
+     * @param <V> type of the map values
+     * @param <M> type of the map
+     * @return a merge function for two maps
+     */
+    private static <K, V, M extends Map<K,V>>
+    BinaryOperator<M> uniqKeysMapMerger() {
+        return (m1, m2) -> {
+            for (Map.Entry<K,V> e : m2.entrySet()) {
+                K k = e.getKey();
+                V v = Objects.requireNonNull(e.getValue());
+                V u = m1.putIfAbsent(k, v);
+                if (u != null) throw duplicateKeyException(k, u, v);
+            }
+            return m1;
+        };
+    }
+
+    /**
+     * {@code BiConsumer<Map, T>} that accumulates (key, value) pairs
+     * extracted from elements into the map, throwing {@code IllegalStateException}
+     * if duplicate keys are encountered.
+     *
+     * @param keyMapper a function that maps an element into a key
+     * @param valueMapper a function that maps an element into a value
+     * @param <T> type of elements
+     * @param <K> type of map keys
+     * @param <V> type of map values
+     * @return an accumulating consumer
+     */
+    private static <T, K, V>
+    BiConsumer<Map<K, V>, T> uniqKeysMapAccumulator(Function<? super T, ? extends K> keyMapper,
+                                                    Function<? super T, ? extends V> valueMapper) {
+        return (map, element) -> {
+            K k = keyMapper.apply(element);
+            V v = Objects.requireNonNull(valueMapper.apply(element));
+            V u = map.putIfAbsent(k, v);
+            if (u != null) throw duplicateKeyException(k, u, v);
+        };
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <I, R> Function<I, R> castingIdentity() {
+        return i -> (R) i;
+    }
+
+    /**
+     * Simple implementation class for {@code Collector}.
+     *
+     * @param <T> the type of elements to be collected
+     * @param <R> the type of the result
+     */
+    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
+        private final Supplier<A> supplier;
+        private final BiConsumer<A, T> accumulator;
+        private final BinaryOperator<A> combiner;
+        private final Function<A, R> finisher;
+        private final Set<Characteristics> characteristics;
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Function<A,R> finisher,
+                      Set<Characteristics> characteristics) {
+            this.supplier = supplier;
+            this.accumulator = accumulator;
+            this.combiner = combiner;
+            this.finisher = finisher;
+            this.characteristics = characteristics;
+        }
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Set<Characteristics> characteristics) {
+            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
+        }
+
+        @Override
+        public BiConsumer<A, T> accumulator() {
+            return accumulator;
+        }
+
+        @Override
+        public Supplier<A> supplier() {
+            return supplier;
+        }
+
+        @Override
+        public BinaryOperator<A> combiner() {
+            return combiner;
+        }
+
+        @Override
+        public Function<A, R> finisher() {
+            return finisher;
+        }
+
+        @Override
+        public Set<Characteristics> characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Collection}, in encounter order.  The {@code Collection} is
+     * created by the provided factory.
+     *
+     * @param <T> the type of the input elements
+     * @param <C> the type of the resulting {@code Collection}
+     * @param collectionFactory a supplier providing a new empty {@code Collection}
+     *                          into which the results will be inserted
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Collection}, in encounter order
+     */
+    public static <T, C extends Collection<T>>
+    Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
+        return new CollectorImpl<>(collectionFactory, Collection<T>::add,
+                                   (r1, r2) -> { r1.addAll(r2); return r1; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code List}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code List} returned; if more
+     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code List}, in encounter order
+     */
+    public static <T>
+    Collector<T, ?, List<T>> toList() {
+        return new CollectorImpl<>(ArrayList::new, List::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter
+     * order. The returned Collector disallows null values and will throw
+     * {@code NullPointerException} if it is presented with a null value.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter order
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    public static <T>
+    Collector<T, ?, List<T>> toUnmodifiableList() {
+        return new CollectorImpl<>(ArrayList::new, List::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   list -> {
+                                       if (list.getClass() == ArrayList.class) { // ensure it's trusted
+                                           return SharedSecrets.getJavaUtilCollectionAccess()
+                                                               .listFromTrustedArray(list.toArray());
+                                       } else {
+                                           throw new IllegalArgumentException();
+                                       }
+                                   },
+                                   CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Set}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Set} returned; if more
+     * control over the returned {@code Set} is required, use
+     * {@link #toCollection(Supplier)}.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Set}
+     */
+    public static <T>
+    Collector<T, ?, Set<T>> toSet() {
+        return new CollectorImpl<>(HashSet::new, Set::add,
+                                   (left, right) -> {
+                                       if (left.size() < right.size()) {
+                                           right.addAll(left); return right;
+                                       } else {
+                                           left.addAll(right); return left;
+                                       }
+                                   },
+                                   CH_UNORDERED_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Set.html#unmodifiable">unmodifiable Set</a>. The returned
+     * Collector disallows null values and will throw {@code NullPointerException}
+     * if it is presented with a null value. If the input contains duplicate elements,
+     * an arbitrary element of the duplicates is preserved.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Set.html#unmodifiable">unmodifiable Set</a>
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    public static <T>
+    Collector<T, ?, Set<T>> toUnmodifiableSet() {
+        return new CollectorImpl<>(HashSet::new, Set::add,
+                                   (left, right) -> {
+                                       if (left.size() < right.size()) {
+                                           right.addAll(left); return right;
+                                       } else {
+                                           left.addAll(right); return left;
+                                       }
+                                   },
+                                   set -> (Set<T>)Set.of(set.toArray()),
+                                   CH_UNORDERED_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order.
+     *
+     * @return a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining() {
+        return new CollectorImpl<CharSequence, StringBuilder, String>(
+                StringBuilder::new, StringBuilder::append,
+                (r1, r2) -> { r1.append(r2); return r1; },
+                StringBuilder::toString, CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
+        return joining(delimiter, "", "");
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, with the specified prefix and
+     * suffix, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @param  prefix the sequence of characters to be used at the beginning
+     *                of the joined result
+     * @param  suffix the sequence of characters to be used at the end
+     *                of the joined result
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
+                                                             CharSequence prefix,
+                                                             CharSequence suffix) {
+        return new CollectorImpl<>(
+                () -> new StringJoiner(delimiter, prefix, suffix),
+                StringJoiner::add, StringJoiner::merge,
+                StringJoiner::toString, CH_NOID);
+    }
+
+    /**
+     * {@code BinaryOperator<Map>} that merges the contents of its right
+     * argument into its left argument, using the provided merge function to
+     * handle duplicate keys.
+     *
+     * @param <K> type of the map keys
+     * @param <V> type of the map values
+     * @param <M> type of the map
+     * @param mergeFunction A merge function suitable for
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()}
+     * @return a merge function for two maps
+     */
+    private static <K, V, M extends Map<K,V>>
+    BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) {
+        return (m1, m2) -> {
+            for (Map.Entry<K,V> e : m2.entrySet())
+                m1.merge(e.getKey(), e.getValue(), mergeFunction);
+            return m1;
+        };
+    }
+
+    /**
+     * Adapts a {@code Collector} accepting elements of type {@code U} to one
+     * accepting elements of type {@code T} by applying a mapping function to
+     * each input element before accumulation.
+     *
+     * @apiNote
+     * The {@code mapping()} collectors are most useful when used in a
+     * multi-level reduction, such as downstream of a {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Person}, to accumulate the set of last names in each city:
+     * <pre>{@code
+     * Map<City, Set<String>> lastNamesByCity
+     *   = people.stream().collect(
+     *     groupingBy(Person::getCity,
+     *                mapping(Person::getLastName,
+     *                        toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> type of elements accepted by downstream collector
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of collector
+     * @param mapper a function to be applied to the input elements
+     * @param downstream a collector which will accept mapped values
+     * @return a collector which applies the mapping function to the input
+     * elements and provides the mapped results to the downstream collector
+     */
+    public static <T, U, A, R>
+    Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
+                               Collector<? super U, A, R> downstream) {
+        BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.supplier(),
+                                   (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
+                                   downstream.combiner(), downstream.finisher(),
+                                   downstream.characteristics());
+    }
+
+    /**
+     * Adapts a {@code Collector} accepting elements of type {@code U} to one
+     * accepting elements of type {@code T} by applying a flat mapping function
+     * to each input element before accumulation.  The flat mapping function
+     * maps an input element to a {@link Stream stream} covering zero or more
+     * output elements that are then accumulated downstream.  Each mapped stream
+     * is {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed downstream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * @apiNote
+     * The {@code flatMapping()} collectors are most useful when used in a
+     * multi-level reduction, such as downstream of a {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Order}, to accumulate the set of line items for each customer:
+     * <pre>{@code
+     * Map<String, Set<LineItem>> itemsByCustomerName
+     *   = orders.stream().collect(
+     *     groupingBy(Order::getCustomerName,
+     *                flatMapping(order -> order.getLineItems().stream(),
+     *                            toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> type of elements accepted by downstream collector
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of collector
+     * @param mapper a function to be applied to the input elements, which
+     * returns a stream of results
+     * @param downstream a collector which will receive the elements of the
+     * stream returned by mapper
+     * @return a collector which applies the mapping function to the input
+     * elements and provides the flat mapped results to the downstream collector
+     * @since 9
+     */
+    public static <T, U, A, R>
+    Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper,
+                                   Collector<? super U, A, R> downstream) {
+        BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.supplier(),
+                            (r, t) -> {
+                                try (Stream<? extends U> result = mapper.apply(t)) {
+                                    if (result != null)
+                                        result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
+                                }
+                            },
+                            downstream.combiner(), downstream.finisher(),
+                            downstream.characteristics());
+    }
+
+    /**
+     * Adapts a {@code Collector} to one accepting elements of the same type
+     * {@code T} by applying the predicate to each input element and only
+     * accumulating if the predicate returns {@code true}.
+     *
+     * @apiNote
+     * The {@code filtering()} collectors are most useful when used in a
+     * multi-level reduction, such as downstream of a {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Employee}, to accumulate the employees in each department that have a
+     * salary above a certain threshold:
+     * <pre>{@code
+     * Map<Department, Set<Employee>> wellPaidEmployeesByDepartment
+     *   = employees.stream().collect(
+     *     groupingBy(Employee::getDepartment,
+     *                filtering(e -> e.getSalary() > 2000,
+     *                          toSet())));
+     * }</pre>
+     * A filtering collector differs from a stream's {@code filter()} operation.
+     * In this example, suppose there are no employees whose salary is above the
+     * threshold in some department.  Using a filtering collector as shown above
+     * would result in a mapping from that department to an empty {@code Set}.
+     * If a stream {@code filter()} operation were done instead, there would be
+     * no mapping for that department at all.
+     *
+     * @param <T> the type of the input elements
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of collector
+     * @param predicate a predicate to be applied to the input elements
+     * @param downstream a collector which will accept values that match the
+     * predicate
+     * @return a collector which applies the predicate to the input elements
+     * and provides matching elements to the downstream collector
+     * @since 9
+     */
+    public static <T, A, R>
+    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
+                                 Collector<? super T, A, R> downstream) {
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.supplier(),
+                                   (r, t) -> {
+                                       if (predicate.test(t)) {
+                                           downstreamAccumulator.accept(r, t);
+                                       }
+                                   },
+                                   downstream.combiner(), downstream.finisher(),
+                                   downstream.characteristics());
+    }
+
+    /**
+     * Adapts a {@code Collector} to perform an additional finishing
+     * transformation.  For example, one could adapt the {@link #toList()}
+     * collector to always produce an immutable list with:
+     * <pre>{@code
+     * List<String> list = people.stream().collect(
+     *   collectingAndThen(toList(),
+     *                     Collections::unmodifiableList));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of the downstream collector
+     * @param <RR> result type of the resulting collector
+     * @param downstream a collector
+     * @param finisher a function to be applied to the final result of the downstream collector
+     * @return a collector which performs the action of the downstream collector,
+     * followed by an additional finishing step
+     */
+    public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
+                                                                Function<R,RR> finisher) {
+        Set<Collector.Characteristics> characteristics = downstream.characteristics();
+        if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            if (characteristics.size() == 1)
+                characteristics = Collectors.CH_NOID;
+            else {
+                characteristics = EnumSet.copyOf(characteristics);
+                characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
+                characteristics = Collections.unmodifiableSet(characteristics);
+            }
+        }
+        return new CollectorImpl<>(downstream.supplier(),
+                                   downstream.accumulator(),
+                                   downstream.combiner(),
+                                   downstream.finisher().andThen(finisher),
+                                   characteristics);
+    }
+
+    /**
+     * Returns a {@code Collector} accepting elements of type {@code T} that
+     * counts the number of input elements.  If no elements are present, the
+     * result is 0.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(0L, e -> 1L, Long::sum)
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that counts the input elements
+     */
+    public static <T> Collector<T, ?, Long>
+    counting() {
+        return summingLong(e -> 1L);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the minimal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.minBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the minimal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    minBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.minBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the maximal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.maxBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the maximal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    maxBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.maxBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Integer>
+    summingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new int[1],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Long>
+    summingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[1],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The sum returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * sum will be {@code NaN}.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    summingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        return new CollectorImpl<>(
+                () -> new double[3],
+                (a, t) -> { double val = mapper.applyAsDouble(t);
+                            sumWithCompensation(a, val);
+                            a[2] += val;},
+                (a, b) -> { sumWithCompensation(a, b[0]);
+                            a[2] += b[2];
+                            // Subtract compensation bits
+                            return sumWithCompensation(a, -b[1]); },
+                a -> computeFinalSum(a),
+                CH_NOID);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensation summation.
+     *
+     * High-order bits of the sum are in intermediateSum[0], low-order
+     * bits of the sum are in intermediateSum[1], any additional
+     * elements are application-specific.
+     *
+     * @param intermediateSum the high-order and low-order words of the intermediate sum
+     * @param value the name value to be included in the running sum
+     */
+    static double[] sumWithCompensation(double[] intermediateSum, double value) {
+        double tmp = value - intermediateSum[1];
+        double sum = intermediateSum[0];
+        double velvel = sum + tmp; // Little wolf of rounding error
+        intermediateSum[1] = (velvel - sum) - tmp;
+        intermediateSum[0] = velvel;
+        return intermediateSum;
+    }
+
+    /**
+     * If the compensated sum is spuriously NaN from accumulating one
+     * or more same-signed infinite values, return the
+     * correctly-signed infinity stored in the simple sum.
+     */
+    static double computeFinalSum(double[] summands) {
+        // Final sum with better error bounds subtract second summand as it is negated
+        double tmp = summands[0] - summands[1];
+        double simpleSum = summands[summands.length - 1];
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be averaged
+     * @return a {@code Collector} that produces the arithmetic mean of a
+     * derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be averaged
+     * @return a {@code Collector} that produces the arithmetic mean of a
+     * derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The average returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * average will be {@code NaN}.
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be averaged
+     * @return a {@code Collector} that produces the arithmetic mean of a
+     * derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the negated low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the number of values seen.
+         */
+        return new CollectorImpl<>(
+                () -> new double[4],
+                (a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;},
+                (a, b) -> {
+                    sumWithCompensation(a, b[0]);
+                    // Subtract compensation bits
+                    sumWithCompensation(a, -b[1]);
+                    a[2] += b[2]; a[3] += b[3];
+                    return a;
+                    },
+                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
+                CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator} using the
+     * provided identity.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(Object, BinaryOperator)}} instead.
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, T>
+    reducing(T identity, BinaryOperator<T> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], t); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0],
+                CH_NOID);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> Supplier<T[]> boxSupplier(T identity) {
+        return () -> (T[]) new Object[] { identity };
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator}.  The result
+     * is described as an {@code Optional<T>}.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate tallest
+     * person in each city:
+     * <pre>{@code
+     * Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
+     * Map<City, Optional<Person>> tallestByCity
+     *   = people.stream().collect(
+     *     groupingBy(Person::getCity,
+     *                reducing(BinaryOperator.maxBy(byHeight))));
+     * }</pre>
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    reducing(BinaryOperator<T> op) {
+        class OptionalBox implements Consumer<T> {
+            T value = null;
+            boolean present = false;
+
+            @Override
+            public void accept(T t) {
+                if (present) {
+                    value = op.apply(value, t);
+                }
+                else {
+                    value = t;
+                    present = true;
+                }
+            }
+        }
+
+        return new CollectorImpl<T, OptionalBox, Optional<T>>(
+                OptionalBox::new, OptionalBox::accept,
+                (a, b) -> { if (b.present) a.accept(b.value); return a; },
+                a -> Optional.ofNullable(a.value), CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified mapping function and
+     * {@code BinaryOperator}. This is a generalization of
+     * {@link #reducing(Object, BinaryOperator)} which allows a transformation
+     * of the elements before reduction.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple map-reduce on a stream,
+     * use {@link Stream#map(Function)} and {@link Stream#reduce(Object, BinaryOperator)}
+     * instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate the longest
+     * last name of residents in each city:
+     * <pre>{@code
+     * Comparator<String> byLength = Comparator.comparing(String::length);
+     * Map<City, String> longestLastNameByCity
+     *   = people.stream().collect(
+     *     groupingBy(Person::getCity,
+     *                reducing("",
+     *                         Person::getLastName,
+     *                         BinaryOperator.maxBy(byLength))));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the mapped values
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param mapper a mapping function to apply to each input value
+     * @param op a {@code BinaryOperator<U>} used to reduce the mapped values
+     * @return a {@code Collector} implementing the map-reduce operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(BinaryOperator)
+     */
+    public static <T, U>
+    Collector<T, ?, U> reducing(U identity,
+                                Function<? super T, ? extends U> mapper,
+                                BinaryOperator<U> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a "group by" operation on
+     * input elements of type {@code T}, grouping elements according to a
+     * classification function, and returning the results in a {@code Map}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code Map<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability, or
+     * thread-safety of the {@code Map} or {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingBy(classifier, toList());
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements appear in the resulting {@code Map}
+     * collector is not required, using {@link #groupingByConcurrent(Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier the classifier function mapping input elements to keys
+     * @return a {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function)
+     */
+    public static <T, K> Collector<T, ?, Map<K, List<T>>>
+    groupingBy(Function<? super T, ? extends K> classifier) {
+        return groupingBy(classifier, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * <p>For example, to compute the set of last names of people in each city:
+     * <pre>{@code
+     * Map<City, Set<String>> namesByCity
+     *   = people.stream().collect(
+     *     groupingBy(Person::getCity,
+     *                mapping(Person::getLastName,
+     *                        toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     * @see #groupingBy(Function)
+     *
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
+                                          Collector<? super T, A, D> downstream) {
+        return groupingBy(classifier, HashMap::new, downstream);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.  The {@code Map} produced by the Collector is created
+     * with the supplied factory function.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     * Map<City, Set<String>> namesByCity
+     *   = people.stream().collect(
+     *     groupingBy(Person::getCity,
+     *                TreeMap::new,
+     *                mapping(Person::getLastName,
+     *                        toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code Map}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a supplier providing a new empty {@code Map}
+     *                   into which the results will be inserted
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, D, A, M extends Map<K, D>>
+    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
+                                  Supplier<M> mapFactory,
+                                  Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
+            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+            downstreamAccumulator.accept(container, t);
+        };
+        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<Map<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code ConcurrentMap} or {@code List} objects returned, or of the
+     * thread-safety of the {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingByConcurrent(classifier, toList());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier a classifier function mapping input elements to keys
+     * @return a concurrent, unordered {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K>
+    Collector<T, ?, ConcurrentMap<K, List<T>>>
+    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code ConcurrentMap<K, D>}.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code ConcurrentMap} returned.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     * ConcurrentMap<City, Set<String>> namesByCity
+     *   = people.stream().collect(
+     *     groupingByConcurrent(Person::getCity,
+     *                          mapping(Person::getLastName,
+     *                                  toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                                              Collector<? super T, A, D> downstream) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.  The {@code ConcurrentMap} produced by the
+     * Collector is created with the supplied factory function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code ConcurrentMap<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     * ConcurrentMap<City, Set<String>> namesByCity
+     *   = people.stream().collect(
+     *     groupingByConcurrent(Person::getCity,
+     *                          ConcurrentSkipListMap::new,
+     *                          mapping(Person::getLastName,
+     *                                  toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a supplier providing a new empty {@code ConcurrentMap}
+     *                   into which the results will be inserted
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D, M extends ConcurrentMap<K, D>>
+    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                            Supplier<M> mapFactory,
+                                            Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
+        BiConsumer<ConcurrentMap<K, A>, T> accumulator;
+        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                downstreamAccumulator.accept(resultContainer, t);
+            };
+        }
+        else {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                synchronized (resultContainer) {
+                    downstreamAccumulator.accept(resultContainer, t);
+                }
+            };
+        }
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, and organizes them into a
+     * {@code Map<Boolean, List<T>>}.
+     *
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
+     * There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} or {@code List}
+     * returned.
+     *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * an empty List.
+     *
+     * @param <T> the type of the input elements
+     * @param predicate a predicate used for classifying input elements
+     * @return a {@code Collector} implementing the partitioning operation
+     *
+     * @see #partitioningBy(Predicate, Collector)
+     */
+    public static <T>
+    Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
+        return partitioningBy(predicate, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, reduces the values in each partition according to
+     * another {@code Collector}, and organizes them into a
+     * {@code Map<Boolean, D>} whose values are the result of the downstream
+     * reduction.
+     *
+     * <p>
+     * The returned {@code Map} always contains mappings for both
+     * {@code false} and {@code true} keys.
+     * There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @apiNote
+     * If a partition has no elements, its value in the result Map will be
+     * obtained by calling the downstream collector's supplier function and then
+     * applying the finisher function.
+     *
+     * @param <T> the type of the input elements
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param predicate a predicate used for classifying input elements
+     * @param downstream a {@code Collector} implementing the downstream
+     *                   reduction
+     * @return a {@code Collector} implementing the cascaded partitioning
+     *         operation
+     *
+     * @see #partitioningBy(Predicate)
+     */
+    public static <T, D, A>
+    Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
+                                                    Collector<? super T, A, D> downstream) {
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Partition<A>, T> accumulator = (result, t) ->
+                downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
+        BinaryOperator<A> op = downstream.combiner();
+        BinaryOperator<Partition<A>> merger = (left, right) ->
+                new Partition<>(op.apply(left.forTrue, right.forTrue),
+                                op.apply(left.forFalse, right.forFalse));
+        Supplier<Partition<A>> supplier = () ->
+                new Partition<>(downstream.supplier().get(),
+                                downstream.supplier().get());
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
+        }
+        else {
+            Function<Partition<A>, Map<Boolean, D>> finisher = par ->
+                    new Partition<>(downstream.finisher().apply(par.forTrue),
+                                    downstream.finisher().apply(par.forFalse));
+            return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
+     * instead.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability,
+     * or thread-safety of the {@code Map} returned.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     * Map<Student, Double> studentToGPA
+     *   = students.stream().collect(
+     *     toMap(Function.identity(),
+     *           student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     * Map<String, Student> studentIdToStudent
+     *   = students.stream().collect(
+     *     toMap(Student::getId,
+     *           Function.identity()));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are inserted into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys and values are the result of applying mapping functions to
+     * the input elements
+     *
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper) {
+        return new CollectorImpl<>(HashMap::new,
+                                   uniqKeysMapAccumulator(keyMapper, valueMapper),
+                                   uniqKeysMapMerger(),
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
+     * whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
+     * to handle merging of the values.
+     *
+     * <p>The returned Collector disallows null keys and values. If either mapping function
+     * returns null, {@code NullPointerException} will be thrown.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys, must be non-null
+     * @param valueMapper a mapping function to produce values, must be non-null
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
+     * are the result of applying the provided mapping functions to the input elements
+     * @throws NullPointerException if either keyMapper or valueMapper is null
+     *
+     * @see #toUnmodifiableMap(Function, Function, BinaryOperator)
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
+                                                Function<? super T, ? extends U> valueMapper) {
+        Objects.requireNonNull(keyMapper, "keyMapper");
+        Objects.requireNonNull(valueMapper, "valueMapper");
+        return collectingAndThen(
+                toMap(keyMapper, valueMapper),
+                map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability,
+     * or thread-safety of the {@code Map} returned.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deal with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     * Map<String, String> phoneBook
+     *   = people.stream().collect(
+     *     toMap(Person::getName,
+     *           Person::getAddress,
+     *           (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper,
+                                    BinaryOperator<U> mergeFunction) {
+        return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
+    }
+
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
+     * whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * <p>The returned Collector disallows null keys and values. If either mapping function
+     * returns null, {@code NullPointerException} will be thrown.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys, must be non-null
+     * @param valueMapper a mapping function to produce values, must be non-null
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)},
+     *                      must be non-null
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
+     * are the result of applying the provided mapping functions to the input elements
+     * @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
+     *
+     * @see #toUnmodifiableMap(Function, Function)
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
+                                                Function<? super T, ? extends U> valueMapper,
+                                                BinaryOperator<U> mergeFunction) {
+        Objects.requireNonNull(keyMapper, "keyMapper");
+        Objects.requireNonNull(valueMapper, "valueMapper");
+        Objects.requireNonNull(mergeFunction, "mergeFunction");
+        return collectingAndThen(
+                toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
+                map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The {@code Map}
+     * is created by a provided supplier function.
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code Map}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapFactory a supplier providing a new empty {@code Map}
+     *                   into which the results will be inserted
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends Map<K, U>>
+    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
+                             Function<? super T, ? extends U> valueMapper,
+                             BinaryOperator<U> mergeFunction,
+                             Supplier<M> mapFactory) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapFactory, accumulator, mapMerger(mergeFunction), CH_ID);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use
+     * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code ConcurrentMap} returned.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code ConcurrentMap} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     * ConcurrentMap<Student, Double> studentToGPA
+     *   = students.stream().collect(
+     *     toConcurrentMap(Function.identity(),
+     *                     student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code ConcurrentMap} mapping a
+     * unique identifier to students:
+     * <pre>{@code
+     * ConcurrentMap<String, Student> studentIdToStudent
+     *   = students.stream().collect(
+     *     toConcurrentMap(Student::getId,
+     *                     Function.identity()));
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper the mapping function to produce keys
+     * @param valueMapper the mapping function to produce values
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to the input elements
+     *
+     * @see #toMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                                        Function<? super T, ? extends U> valueMapper) {
+        return new CollectorImpl<>(ConcurrentHashMap::new,
+                                   uniqKeysMapAccumulator(keyMapper, valueMapper),
+                                   uniqKeysMapMerger(),
+                                   CH_CONCURRENT_ID);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code ConcurrentMap} returned.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toConcurrentMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deal with these collisions, and produce a
+     * {@code ConcurrentMap} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     * ConcurrentMap<String, String> phoneBook
+     *   = people.stream().collect(
+     *     toConcurrentMap(Person::getName,
+     *                     Person::getAddress,
+     *                     (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>>
+    toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                    Function<? super T, ? extends U> valueMapper,
+                    BinaryOperator<U> mergeFunction) {
+        return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The
+     * {@code ConcurrentMap} is created by a provided supplier function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapFactory a supplier providing a new empty {@code ConcurrentMap}
+     *                   into which the results will be inserted
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends ConcurrentMap<K, U>>
+    Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                       Function<? super T, ? extends U> valueMapper,
+                                       BinaryOperator<U> mergeFunction,
+                                       Supplier<M> mapFactory) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapFactory, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code int}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingLong(ToLongFunction)
+     */
+    public static <T>
+    Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
+                IntSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsInt(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code long}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper the mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
+                LongSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsLong(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code double}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingLong(ToLongFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
+        return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
+                DoubleSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsDouble(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that is a composite of two downstream collectors.
+     * Every element passed to the resulting collector is processed by both downstream
+     * collectors, then their results are merged using the specified merge function
+     * into the final result.
+     *
+     * <p>The resulting collector functions do the following:
+     *
+     * <ul>
+     * <li>supplier: creates a result container that contains result containers
+     * obtained by calling each collector's supplier
+     * <li>accumulator: calls each collector's accumulator with its result container
+     * and the input element
+     * <li>combiner: calls each collector's combiner with two result containers
+     * <li>finisher: calls each collector's finisher with its result container,
+     * then calls the supplied merger and returns its result.
+     * </ul>
+     *
+     * <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both downstream
+     * collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both downstream
+     * collectors are concurrent.
+     *
+     * @param <T>         the type of the input elements
+     * @param <R1>        the result type of the first collector
+     * @param <R2>        the result type of the second collector
+     * @param <R>         the final result type
+     * @param downstream1 the first downstream collector
+     * @param downstream2 the second downstream collector
+     * @param merger      the function which merges two results into the single one
+     * @return a {@code Collector} which aggregates the results of two supplied collectors.
+     * @since 12
+     */
+    public static <T, R1, R2, R>
+    Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
+                              Collector<? super T, ?, R2> downstream2,
+                              BiFunction<? super R1, ? super R2, R> merger) {
+        return teeing0(downstream1, downstream2, merger);
+    }
+
+    private static <T, A1, A2, R1, R2, R>
+    Collector<T, ?, R> teeing0(Collector<? super T, A1, R1> downstream1,
+                               Collector<? super T, A2, R2> downstream2,
+                               BiFunction<? super R1, ? super R2, R> merger) {
+        Objects.requireNonNull(downstream1, "downstream1");
+        Objects.requireNonNull(downstream2, "downstream2");
+        Objects.requireNonNull(merger, "merger");
+
+        Supplier<A1> c1Supplier = Objects.requireNonNull(downstream1.supplier(), "downstream1 supplier");
+        Supplier<A2> c2Supplier = Objects.requireNonNull(downstream2.supplier(), "downstream2 supplier");
+        BiConsumer<A1, ? super T> c1Accumulator =
+                Objects.requireNonNull(downstream1.accumulator(), "downstream1 accumulator");
+        BiConsumer<A2, ? super T> c2Accumulator =
+                Objects.requireNonNull(downstream2.accumulator(), "downstream2 accumulator");
+        BinaryOperator<A1> c1Combiner = Objects.requireNonNull(downstream1.combiner(), "downstream1 combiner");
+        BinaryOperator<A2> c2Combiner = Objects.requireNonNull(downstream2.combiner(), "downstream2 combiner");
+        Function<A1, R1> c1Finisher = Objects.requireNonNull(downstream1.finisher(), "downstream1 finisher");
+        Function<A2, R2> c2Finisher = Objects.requireNonNull(downstream2.finisher(), "downstream2 finisher");
+
+        Set<Collector.Characteristics> characteristics;
+        Set<Collector.Characteristics> c1Characteristics = downstream1.characteristics();
+        Set<Collector.Characteristics> c2Characteristics = downstream2.characteristics();
+        if (CH_ID.containsAll(c1Characteristics) || CH_ID.containsAll(c2Characteristics)) {
+            characteristics = CH_NOID;
+        } else {
+            EnumSet<Collector.Characteristics> c = EnumSet.noneOf(Collector.Characteristics.class);
+            c.addAll(c1Characteristics);
+            c.retainAll(c2Characteristics);
+            c.remove(Collector.Characteristics.IDENTITY_FINISH);
+            characteristics = Collections.unmodifiableSet(c);
+        }
+
+        class PairBox {
+            A1 left = c1Supplier.get();
+            A2 right = c2Supplier.get();
+
+            void add(T t) {
+                c1Accumulator.accept(left, t);
+                c2Accumulator.accept(right, t);
+            }
+
+            PairBox combine(PairBox other) {
+                left = c1Combiner.apply(left, other.left);
+                right = c2Combiner.apply(right, other.right);
+                return this;
+            }
+
+            R get() {
+                R1 r1 = c1Finisher.apply(left);
+                R2 r2 = c2Finisher.apply(right);
+                return merger.apply(r1, r2);
+            }
+        }
+
+        return new CollectorImpl<>(PairBox::new, PairBox::add, PairBox::combine, PairBox::get, characteristics);
+    }
+
+    /**
+     * Implementation class used by partitioningBy.
+     */
+    private static final class Partition<T>
+            extends AbstractMap<Boolean, T>
+            implements Map<Boolean, T> {
+        final T forTrue;
+        final T forFalse;
+
+        Partition(T forTrue, T forFalse) {
+            this.forTrue = forTrue;
+            this.forFalse = forFalse;
+        }
+
+        @Override
+        public Set<Map.Entry<Boolean, T>> entrySet() {
+            return new AbstractSet<>() {
+                @Override
+                public Iterator<Map.Entry<Boolean, T>> iterator() {
+                    Map.Entry<Boolean, T> falseEntry = new SimpleImmutableEntry<>(false, forFalse);
+                    Map.Entry<Boolean, T> trueEntry = new SimpleImmutableEntry<>(true, forTrue);
+                    return List.of(falseEntry, trueEntry).iterator();
+                }
+
+                @Override
+                public int size() {
+                    return 2;
+                }
+            };
+        }
+    }
+}
diff --git a/android-35/java/util/stream/DistinctOps.java b/android-35/java/util/stream/DistinctOps.java
new file mode 100644
index 0000000..e299b75
--- /dev/null
+++ b/android-35/java/util/stream/DistinctOps.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.IntFunction;
+
+/**
+ * Factory methods for transforming streams into duplicate-free streams, using
+ * {@link Object#equals(Object)} to determine equality.
+ *
+ * @since 1.8
+ */
+final class DistinctOps {
+
+    private DistinctOps() { }
+
+    /**
+     * Appends a "distinct" operation to the provided stream, and returns the
+     * new stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @return the new stream
+     */
+    static <T> ReferencePipeline<T, T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      StreamOpFlag.IS_DISTINCT | StreamOpFlag.NOT_SIZED) {
+
+            <P_IN> Node<T> reduce(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                // If the stream is SORTED then it should also be ORDERED so the following will also
+                // preserve the sort order
+                TerminalOp<T, LinkedHashSet<T>> reduceOp
+                        = ReduceOps.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add,
+                                                                 LinkedHashSet::addAll);
+                return Nodes.node(reduceOp.evaluateParallel(helper, spliterator));
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.evaluate(spliterator, false, generator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return reduce(helper, spliterator);
+                }
+                else {
+                    // Holder of null state since ConcurrentHashMap does not support null values
+                    AtomicBoolean seenNull = new AtomicBoolean(false);
+                    ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap<>();
+                    TerminalOp<T, Void> forEachOp = ForEachOps.makeRef(t -> {
+                        if (t == null)
+                            seenNull.set(true);
+                        else
+                            map.putIfAbsent(t, Boolean.TRUE);
+                    }, false);
+                    forEachOp.evaluateParallel(helper, spliterator);
+
+                    // If null has been seen then copy the key set into a HashSet that supports null values
+                    // and add null
+                    Set<T> keys = map.keySet();
+                    if (seenNull.get()) {
+                        // TODO Implement a more efficient set-union view, rather than copying
+                        keys = new HashSet<>(keys);
+                        keys.add(null);
+                    }
+                    return Nodes.node(keys);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.wrapSpliterator(spliterator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    // Not lazy, barrier required to preserve order
+                    return reduce(helper, spliterator).spliterator();
+                }
+                else {
+                    // Lazy
+                    return new StreamSpliterators.DistinctSpliterator<>(helper.wrapSpliterator(spliterator));
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                Objects.requireNonNull(sink);
+
+                if (StreamOpFlag.DISTINCT.isKnown(flags)) {
+                    return sink;
+                } else if (StreamOpFlag.SORTED.isKnown(flags)) {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        boolean seenNull;
+                        T lastSeen;
+
+                        @Override
+                        public void begin(long size) {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (t == null) {
+                                if (!seenNull) {
+                                    seenNull = true;
+                                    downstream.accept(lastSeen = null);
+                                }
+                            } else if (lastSeen == null || !t.equals(lastSeen)) {
+                                downstream.accept(lastSeen = t);
+                            }
+                        }
+                    };
+                } else {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        Set<T> seen;
+
+                        @Override
+                        public void begin(long size) {
+                            seen = new HashSet<>();
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (seen.add(t)) {
+                                downstream.accept(t);
+                            }
+                        }
+                    };
+                }
+            }
+        };
+    }
+}
diff --git a/android-35/java/util/stream/DoublePipeline.java b/android-35/java/util/stream/DoublePipeline.java
new file mode 100644
index 0000000..e3c89b5
--- /dev/null
+++ b/android-35/java/util/stream/DoublePipeline.java
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code double}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class DoublePipeline<E_IN>
+        extends AbstractPipeline<E_IN, Double, DoubleStream>
+        implements DoubleStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Supplier<? extends Spliterator<Double>> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Spliterator<Double> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    DoublePipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Double> to a {@code DoubleConsumer}, ideally simply
+     * by casting.
+     */
+    private static DoubleConsumer adapt(Sink<Double> sink) {
+        if (sink instanceof DoubleConsumer) {
+            return (DoubleConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Sink<Double> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Double>} to a {@code Spliterator.OfDouble}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfDouble, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfDouble adapt(Spliterator<Double> s) {
+        if (s instanceof Spliterator.OfDouble) {
+            return (Spliterator.OfDouble) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Spliterator<Double> s)");
+            throw new UnsupportedOperationException("DoubleStream.adapt(Spliterator<Double> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Double> evaluateToNode(PipelineHelper<Double> helper,
+                                             Spliterator<P_IN> spliterator,
+                                             boolean flattenTree,
+                                             IntFunction<Double[]> generator) {
+        return Nodes.collectDouble(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Double> wrap(PipelineHelper<Double> ph,
+                                          Supplier<Spliterator<P_IN>> supplier,
+                                          boolean isParallel) {
+        return new StreamSpliterators.DoubleWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfDouble lazySpliterator(Supplier<? extends Spliterator<Double>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfDouble((Supplier<Spliterator.OfDouble>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final boolean forEachWithCancel(Spliterator<Double> spliterator, Sink<Double> sink) {
+        Spliterator.OfDouble spl = adapt(spliterator);
+        DoubleConsumer adaptedSink = adapt(sink);
+        boolean cancelled;
+        do { } while (!(cancelled = sink.cancellationRequested()) && spl.tryAdvance(adaptedSink));
+        return cancelled;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Double> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Double[]> generator) {
+        return Nodes.doubleBuilder(exactSizeIfKnown);
+    }
+
+    private <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE, opFlags) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedDouble<U>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    // DoubleStream
+
+    @Override
+    public final PrimitiveIterator.OfDouble iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfDouble spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from DoubleStream
+
+    @Override
+    public final Stream<Double> boxed() {
+        return mapToObj(Double::valueOf, 0);
+    }
+
+    @Override
+    public final DoubleStream map(DoubleUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
+    }
+
+    @Override
+    public final IntStream mapToInt(DoubleToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedDouble<Integer>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(DoubleToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedDouble<Long>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    DoubleConsumer downstreamAsDouble = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        try (DoubleStream result = mapper.apply(t)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsDouble);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsDouble));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        // If this method is called then an operation within the stream
+                        // pipeline is short-circuiting (see AbstractPipeline.copyInto).
+                        // Note that we cannot differentiate between an upstream or
+                        // downstream operation
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapMulti(DoubleMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<>(this, StreamShape.DOUBLE_VALUE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(double t) {
+                            mapper.accept(t, (DoubleConsumer) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public DoubleStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream filter(DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream peek(DoubleConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from DoubleStream
+
+    @Override
+    public final DoubleStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeDouble(this, (long) 0, maxSize);
+    }
+
+    @Override
+    public final DoubleStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else {
+            long limit = -1;
+            return SliceOps.makeDouble(this, n, limit);
+        }
+    }
+
+    @Override
+    public final DoubleStream takeWhile(DoublePredicate predicate) {
+        return WhileOps.makeTakeWhileDouble(this, predicate);
+    }
+
+    @Override
+    public final DoubleStream dropWhile(DoublePredicate predicate) {
+        return WhileOps.makeDropWhileDouble(this, predicate);
+    }
+
+    @Override
+    public final DoubleStream sorted() {
+        return SortedOps.makeDouble(this);
+    }
+
+    @Override
+    public final DoubleStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a double-specific map/set implementation.
+        return boxed().distinct().mapToDouble(i -> (double) i);
+    }
+
+    // Terminal ops from DoubleStream
+
+    @Override
+    public void forEach(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, false));
+    }
+
+    @Override
+    public void forEachOrdered(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, true));
+    }
+
+    @Override
+    public final double sum() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the negated low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        double[] summation = collect(() -> new double[3],
+                               (ll, d) -> {
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[2] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   // Subtract compensation bits
+                                   Collectors.sumWithCompensation(ll, -rr[1]);
+                                   ll[2] += rr[2];
+                               });
+
+        return Collectors.computeFinalSum(summation);
+    }
+
+    @Override
+    public final OptionalDouble min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalDouble max() {
+        return reduce(Math::max);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     */
+    @Override
+    public final OptionalDouble average() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, index 2 holds the number of values seen, index 3
+         * holds the simple sum.
+         */
+        double[] avg = collect(() -> new double[4],
+                               (ll, d) -> {
+                                   ll[2]++;
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[3] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   // Subtract compensation bits
+                                   Collectors.sumWithCompensation(ll, -rr[1]);
+                                   ll[2] += rr[2];
+                                   ll[3] += rr[3];
+                               });
+        return avg[2] > 0
+            ? OptionalDouble.of(Collectors.computeFinalSum(avg) / avg[2])
+            : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return evaluate(ReduceOps.makeDoubleCounting());
+    }
+
+    @Override
+    public final DoubleSummaryStatistics summaryStatistics() {
+        return collect(DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept,
+                       DoubleSummaryStatistics::combine);
+    }
+
+    @Override
+    public final double reduce(double identity, DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(identity, op));
+    }
+
+    @Override
+    public final OptionalDouble reduce(DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjDoubleConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        Objects.requireNonNull(combiner);
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalDouble findFirst() {
+        return evaluate(FindOps.makeDouble(true));
+    }
+
+    @Override
+    public final OptionalDouble findAny() {
+        return evaluate(FindOps.makeDouble(false));
+    }
+
+    @Override
+    public final double[] toArray() {
+        return Nodes.flattenDouble((Node.OfDouble) evaluateToArrayNode(Double[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of a DoubleStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Double>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Double> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Double> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEach(consumer);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEachOrdered(consumer);
+            }
+        }
+
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateful intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                        Spliterator<P_IN> spliterator,
+                                                        IntFunction<Double[]> generator);
+    }
+}
diff --git a/android-35/java/util/stream/DoubleStream.java b/android-35/java/util/stream/DoubleStream.java
new file mode 100644
index 0000000..fde242c
--- /dev/null
+++ b/android-35/java/util/stream/DoubleStream.java
@@ -0,0 +1,1246 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleSupplier;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.Function;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive double-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code double} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     double sum = widgets.stream()
+ *                         .filter(w -> w.getColor() == RED)
+ *                         .mapToDouble(w -> w.getWeight())
+ *                         .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface DoubleStream extends BaseStream<Double, DoubleStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    DoubleStream filter(DoublePredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream map(DoubleUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(DoubleToIntFunction mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(DoubleToLongFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code DoubleStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with multiple elements, specifically zero or more elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain DoubleConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain DoubleConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMap flatMap} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with a {@code DoubleConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates a {@code DoubleStream} from the
+     * internal buffer. Finally, it returns this stream to {@code flatMap}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see Stream#mapMulti Stream.mapMulti
+     * @since 16
+     */
+    default DoubleStream mapMulti(DoubleMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMap(e -> {
+            SpinedBuffer.OfDouble buffer = new SpinedBuffer.OfDouble();
+            mapper.accept(e, buffer);
+            return StreamSupport.doubleStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream. The
+     * elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order. The elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     DoubleStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * <p>In cases where the stream implementation is able to optimize away the
+     * production of some or all the elements (such as with short-circuiting
+     * operations like {@code findFirst}, or in the example described in
+     * {@link #count}), the action will not be invoked for those elements.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    DoubleStream peek(DoubleConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    DoubleStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    DoubleStream skip(long n);
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the longest
+     * prefix of elements taken from this stream that match the given predicate.
+     * Otherwise returns, if this stream is unordered, a stream consisting of a
+     * subset of elements taken from this stream that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to take any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * takes all elements (the result is the same as the input), or if no
+     * elements of the stream match the given predicate then no elements are
+     * taken (the result is an empty stream).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code takeWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as
+     * {@link #generate(DoubleSupplier)}) or removing the ordering constraint
+     * with {@link #unordered()} may result in significant speedups of
+     * {@code takeWhile()} in parallel pipelines, if the semantics of your
+     * situation permit.  If consistency with encounter order is required, and
+     * you are experiencing poor performance or memory utilization with
+     * {@code takeWhile()} in parallel pipelines, switching to sequential
+     * execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default DoubleStream takeWhile(DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.doubleStream(
+                new WhileOps.UnorderedWhileSpliterator.OfDouble.Taking(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the remaining
+     * elements of this stream after dropping the longest prefix of elements
+     * that match the given predicate.  Otherwise returns, if this stream is
+     * unordered, a stream consisting of the remaining elements of this stream
+     * after dropping a subset of elements that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to drop any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * drops all elements (the result is an empty stream), or if no elements of
+     * the stream match the given predicate then no elements are dropped (the
+     * result is the same as the input).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code dropWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as
+     * {@link #generate(DoubleSupplier)}) or removing the ordering constraint
+     * with {@link #unordered()} may result in significant speedups of
+     * {@code dropWhile()} in parallel pipelines, if the semantics of your
+     * situation permit.  If consistency with encounter order is required, and
+     * you are experiencing poor performance or memory utilization with
+     * {@code dropWhile()} in parallel pipelines, switching to sequential
+     * execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default DoubleStream dropWhile(DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.doubleStream(
+                new WhileOps.UnorderedWhileSpliterator.OfDouble.Dropping(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(DoubleConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(DoubleConsumer)
+     */
+    void forEachOrdered(DoubleConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    double[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     double result = identity;
+     *     for (double element : this stream)
+     *         result = accumulator.applyAsDouble(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, Double::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    double reduce(double identity, DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalDouble} describing the reduced
+     * value, if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     double result = null;
+     *     for (double element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsDouble(result, element);
+     *     }
+     *     return foundAny ? OptionalDouble.of(result) : OptionalDouble.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(double, DoubleBinaryOperator)
+     */
+    OptionalDouble reduce(DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (double element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(double, DoubleBinaryOperator)}, {@code collect}
+     * operations can be parallelized without requiring additional
+     * synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> the type of the mutable result container
+     * @param supplier a function that creates a new mutable result container.
+     *                 For a parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that must fold an element into a result
+     *                    container.
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that accepts two partial result containers
+     *                    and merges them, which must be compatible with the
+     *                    accumulator function.  The combiner function must fold
+     *                    the elements from the second result container into the
+     *                    first result container.
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjDoubleConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.
+     *
+     * Summation is a special case of a <a
+     * href="package-summary.html#Reduction">reduction</a>. If
+     * floating-point summation were exact, this method would be
+     * equivalent to:
+     *
+     * <pre>{@code
+     *     return reduce(0, Double::sum);
+     * }</pre>
+     *
+     * However, since floating-point summation is not exact, the above
+     * code is not necessarily equivalent to the summation computation
+     * done by this method.
+     *
+     * <p>The value of a floating-point sum is a function both
+     * of the input values as well as the order of addition
+     * operations. The order of addition operations of this method is
+     * intentionally not defined to allow for implementation
+     * flexibility to improve the speed and accuracy of the computed
+     * result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * Because of the unspecified order of operations and the
+     * possibility of using differing summation schemes, the output of
+     * this method may vary on the same input elements.
+     *
+     * <p>Various conditions can result in a non-finite sum being
+     * computed. This can occur even if the all the elements
+     * being summed are finite. If any element is non-finite,
+     * the sum will be non-finite:
+     *
+     * <ul>
+     *
+     * <li>If any element is a NaN, then the final sum will be
+     * NaN.
+     *
+     * <li>If the elements contain one or more infinities, the
+     * sum will be infinite or NaN.
+     *
+     * <ul>
+     *
+     * <li>If the elements contain infinities of opposite sign,
+     * the sum will be NaN.
+     *
+     * <li>If the elements contain infinities of one sign and
+     * an intermediate sum overflows to an infinity of the opposite
+     * sign, the sum may be NaN.
+     *
+     * </ul>
+     *
+     * </ul>
+     *
+     * It is possible for intermediate sums of finite values to
+     * overflow into opposite-signed infinities; if that occurs, the
+     * final sum will be NaN even if the elements are all
+     * finite.
+     *
+     * If all the elements are zero, the sign of zero is
+     * <em>not</em> guaranteed to be preserved in the final sum.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return the sum of elements in this stream
+     */
+    double sum();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the minimum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The minimum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the minimum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble min();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the maximum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The maximum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the maximum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @apiNote
+     * An implementation may choose to not execute the stream pipeline (either
+     * sequentially or in parallel) if it is capable of computing the count
+     * directly from the stream source.  In such cases no source elements will
+     * be traversed and no intermediate operations will be evaluated.
+     * Behavioral parameters with side-effects, which are strongly discouraged
+     * except for harmless cases such as debugging, may be affected.  For
+     * example, consider the following stream:
+     * <pre>{@code
+     *     DoubleStream s = DoubleStream.of(1, 2, 3, 4);
+     *     long count = s.peek(System.out::println).count();
+     * }</pre>
+     * The number of elements covered by the stream source is known and the
+     * intermediate operation, {@code peek}, does not inject into or remove
+     * elements from the stream (as may be the case for {@code flatMap} or
+     * {@code filter} operations).  Thus the count is 4 and there is no need to
+     * execute the pipeline and, as a side-effect, print out the elements.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic
+     * mean of elements of this stream, or an empty optional if this
+     * stream is empty.
+     *
+     * <p>The computed average can vary numerically and have the
+     * special case behavior as computing the sum; see {@link #sum}
+     * for details.
+     *
+     *  <p>The average is a special case of a <a
+     *  href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    DoubleSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(DoublePredicate predicate);
+
+    /**
+     * Returns an {@link OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty.  If
+     * the stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty
+     */
+    OptionalDouble findFirst();
+
+    /**
+     * Returns an {@link OptionalDouble} describing some element of the stream,
+     * or an empty {@code OptionalDouble} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalDouble} describing some element of this stream,
+     * or an empty {@code OptionalDouble} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalDouble findAny();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * boxed to {@code Double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to a {@code Double}
+     */
+    Stream<Double> boxed();
+
+    @Override
+    DoubleStream sequential();
+
+    @Override
+    DoubleStream parallel();
+
+    @Override
+    PrimitiveIterator.OfDouble iterator();
+
+    @Override
+    Spliterator.OfDouble spliterator();
+
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code DoubleStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.DoubleStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code DoubleStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static DoubleStream empty() {
+        return StreamSupport.doubleStream(Spliterators.emptyDoubleSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static DoubleStream of(double t) {
+        return StreamSupport.doubleStream(new Streams.DoubleStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static DoubleStream of(double... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code DoubleStream}
+     * will be the provided {@code seed}.  For {@code n > 0}, the element at
+     * position {@code n}, will be the result of applying the function {@code f}
+     *  to the element at position {@code n - 1}.
+     *
+     * <p>The action of applying {@code f} for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying {@code f} for subsequent elements.  For any given
+     * element the action may be performed in whatever thread the library
+     * chooses.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code DoubleStream}
+     */
+    public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) {
+        Objects.requireNonNull(f);
+        Spliterator.OfDouble spliterator = new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            double prev;
+            boolean started;
+
+            @Override
+            public boolean tryAdvance(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+                double t;
+                if (started)
+                    t = f.applyAsDouble(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+        };
+        return StreamSupport.doubleStream(spliterator, false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code DoubleStream} produced by iterative
+     * application of the given {@code next} function to an initial element,
+     * conditioned on satisfying the given {@code hasNext} predicate.  The
+     * stream terminates as soon as the {@code hasNext} predicate returns false.
+     *
+     * <p>{@code DoubleStream.iterate} should produce the same sequence of elements as
+     * produced by the corresponding for-loop:
+     * <pre>{@code
+     *     for (double index=seed; hasNext.test(index); index = next.applyAsDouble(index)) {
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * <p>The resulting sequence may be empty if the {@code hasNext} predicate
+     * does not hold on the seed value.  Otherwise the first element will be the
+     * supplied {@code seed} value, the next element (if present) will be the
+     * result of applying the {@code next} function to the {@code seed} value,
+     * and so on iteratively until the {@code hasNext} predicate indicates that
+     * the stream should terminate.
+     *
+     * <p>The action of applying the {@code hasNext} predicate to an element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying the {@code next} function to that element.  The
+     * action of applying the {@code next} function for one element
+     * <i>happens-before</i> the action of applying the {@code hasNext}
+     * predicate for subsequent elements.  For any given element an action may
+     * be performed in whatever thread the library chooses.
+     *
+     * @param seed the initial element
+     * @param hasNext a predicate to apply to elements to determine when the
+     *                stream must terminate.
+     * @param next a function to be applied to the previous element to produce
+     *             a new element
+     * @return a new sequential {@code DoubleStream}
+     * @since 9
+     */
+    public static DoubleStream iterate(double seed, DoublePredicate hasNext, DoubleUnaryOperator next) {
+        Objects.requireNonNull(next);
+        Objects.requireNonNull(hasNext);
+        Spliterator.OfDouble spliterator = new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            double prev;
+            boolean started, finished;
+
+            @Override
+            public boolean tryAdvance(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return false;
+                double t;
+                if (started)
+                    t = next.applyAsDouble(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                if (!hasNext.test(t)) {
+                    finished = true;
+                    return false;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return;
+                finished = true;
+                double t = started ? next.applyAsDouble(prev) : seed;
+                while (hasNext.test(t)) {
+                    action.accept(t);
+                    t = next.applyAsDouble(t);
+                }
+            }
+        };
+        return StreamSupport.doubleStream(spliterator, false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code DoubleSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code DoubleSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code DoubleStream}
+     */
+    public static DoubleStream generate(DoubleSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.doubleStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfDouble(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * <p>This method operates on the two input streams and binds each stream
+     * to its source.  As a result subsequent modifications to an input stream
+     * source may not be reflected in the concatenated stream result.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowError}.
+     *
+     * @apiNote
+     * To preserve optimization opportunities this method binds each stream to
+     * its source and accepts only two streams as parameters.  For example, the
+     * exact size of the concatenated stream source can be computed if the exact
+     * size of each input stream source is known.
+     * To concatenate more streams without binding, or without nested calls to
+     * this method, try creating a stream of streams and flat-mapping with the
+     * identity function, for example:
+     * <pre>{@code
+     *     DoubleStream concat = Stream.of(s1, s2, s3, s4).flatMapToDouble(s -> s);
+     * }</pre>
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static DoubleStream concat(DoubleStream a, DoubleStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
+                a.spliterator(), b.spliterator());
+        DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code DoubleStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see DoubleStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends DoubleConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(double t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(double t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        DoubleStream build();
+    }
+
+    /**
+     * Represents an operation that accepts a {@code double}-valued argument
+     * and a DoubleConsumer, and returns no result. This functional interface is
+     * used by {@link DoubleStream#mapMulti(DoubleMapMultiConsumer) DoubleStream.mapMulti}
+     * to replace a double value with zero or more double values.
+     *
+     * <p>This is a <a href="../function/package-summary.html">functional interface</a>
+     * whose functional method is {@link #accept(double, DoubleConsumer)}.
+     *
+     * @see DoubleStream#mapMulti(DoubleMapMultiConsumer)
+     *
+     * @since 16
+     */
+    @FunctionalInterface
+    interface DoubleMapMultiConsumer {
+
+        /**
+         * Replaces the given {@code value} with zero or more values by feeding the mapped
+         * values to the {@code dc} consumer.
+         *
+         * @param value the double value coming from upstream
+         * @param dc a {@code DoubleConsumer} accepting the mapped values
+         */
+        void accept(double value, DoubleConsumer dc);
+    }
+}
diff --git a/android-35/java/util/stream/FindOps.java b/android-35/java/util/stream/FindOps.java
new file mode 100644
index 0000000..299cebe
--- /dev/null
+++ b/android-35/java/util/stream/FindOps.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that searches
+ * for an element in a stream pipeline, and terminates when it finds one.
+ * Supported variants include find-first (find the first element in the
+ * encounter order) and find-any (find any element, may not be the first in
+ * encounter order.)
+ *
+ * @since 1.8
+ */
+final class FindOps {
+
+    private FindOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of objects.
+     *
+     * @param <T> the type of elements of the stream
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> TerminalOp<T, Optional<T>> makeRef(boolean mustFindFirst) {
+        return (TerminalOp<T, Optional<T>>)
+                (mustFindFirst ? FindSink.OfRef.OP_FIND_FIRST : FindSink.OfRef.OP_FIND_ANY);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of ints.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Integer, OptionalInt> makeInt(boolean mustFindFirst) {
+        return mustFindFirst ? FindSink.OfInt.OP_FIND_FIRST : FindSink.OfInt.OP_FIND_ANY;
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of longs.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Long, OptionalLong> makeLong(boolean mustFindFirst) {
+        return mustFindFirst ? FindSink.OfLong.OP_FIND_FIRST : FindSink.OfLong.OP_FIND_ANY;
+    }
+
+    /**
+     * Constructs a {@code FindOp} for streams of doubles.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Double, OptionalDouble> makeDouble(boolean mustFindFirst) {
+        return mustFindFirst ? FindSink.OfDouble.OP_FIND_FIRST : FindSink.OfDouble.OP_FIND_ANY;
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that searches for an element in a
+     * stream pipeline, and terminates when it finds one.  Implements both
+     * find-first (find the first element in the encounter order) and find-any
+     * (find any element, may not be the first in encounter order.)
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <O> the result type of the find operation, typically an optional
+     *        type
+     */
+    private static final class FindOp<T, O> implements TerminalOp<T, O> {
+        private final StreamShape shape;
+        final int opFlags;
+        final O emptyValue;
+        final Predicate<O> presentPredicate;
+        final Supplier<TerminalSink<T, O>> sinkSupplier;
+
+        /**
+         * Constructs a {@code FindOp}.
+         *
+         * @param mustFindFirst if true, must find the first element in
+         *        encounter order, otherwise can find any element
+         * @param shape stream shape of elements to search
+         * @param emptyValue result value corresponding to "found nothing"
+         * @param presentPredicate {@code Predicate} on result value
+         *        corresponding to "found something"
+         * @param sinkSupplier supplier for a {@code TerminalSink} implementing
+         *        the matching functionality
+         */
+        FindOp(boolean mustFindFirst,
+                       StreamShape shape,
+                       O emptyValue,
+                       Predicate<O> presentPredicate,
+                       Supplier<TerminalSink<T, O>> sinkSupplier) {
+            this.opFlags = StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
+            this.shape = shape;
+            this.emptyValue = emptyValue;
+            this.presentPredicate = presentPredicate;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return opFlags;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+
+        @Override
+        public <S> O evaluateSequential(PipelineHelper<T> helper,
+                                        Spliterator<S> spliterator) {
+            O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
+            return result != null ? result : emptyValue;
+        }
+
+        @Override
+        public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            // This takes into account the upstream ops flags and the terminal
+            // op flags and therefore takes into account findFirst or findAny
+            boolean mustFindFirst = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
+            return new FindTask<>(this, mustFindFirst, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Implementation of @{code TerminalSink} that implements the find
+     * functionality, requesting cancellation when something has been found
+     *
+     * @param <T> The type of input element
+     * @param <O> The result type, typically an optional type
+     */
+    private abstract static class FindSink<T, O> implements TerminalSink<T, O> {
+        boolean hasValue;
+        T value;
+
+        FindSink() {} // Avoid creation of special accessor
+
+        @Override
+        public void accept(T value) {
+            if (!hasValue) {
+                hasValue = true;
+                this.value = value;
+            }
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return hasValue;
+        }
+
+        /** Specialization of {@code FindSink} for reference streams */
+        static final class OfRef<T> extends FindSink<T, Optional<T>> {
+            @Override
+            public Optional<T> get() {
+                return hasValue ? Optional.of(value) : null;
+            }
+
+            static final TerminalOp<?, ?> OP_FIND_FIRST = new FindOp<>(true,
+                    StreamShape.REFERENCE, Optional.empty(),
+                    Optional::isPresent, FindSink.OfRef::new);
+
+            static final TerminalOp<?, ?> OP_FIND_ANY = new FindOp<>(false,
+                    StreamShape.REFERENCE, Optional.empty(),
+                    Optional::isPresent, FindSink.OfRef::new);
+        }
+
+        /** Specialization of {@code FindSink} for int streams */
+        static final class OfInt extends FindSink<Integer, OptionalInt>
+                implements Sink.OfInt {
+            @Override
+            public void accept(int value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Integer) value);
+            }
+
+            @Override
+            public OptionalInt get() {
+                return hasValue ? OptionalInt.of(value) : null;
+            }
+
+            static final TerminalOp<Integer, OptionalInt> OP_FIND_FIRST = new FindOp<>(true,
+                    StreamShape.INT_VALUE, OptionalInt.empty(),
+                    OptionalInt::isPresent, FindSink.OfInt::new);
+            static final TerminalOp<Integer, OptionalInt> OP_FIND_ANY = new FindOp<>(false,
+                    StreamShape.INT_VALUE, OptionalInt.empty(),
+                    OptionalInt::isPresent, FindSink.OfInt::new);
+        }
+
+        /** Specialization of {@code FindSink} for long streams */
+        static final class OfLong extends FindSink<Long, OptionalLong>
+                implements Sink.OfLong {
+            @Override
+            public void accept(long value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Long) value);
+            }
+
+            @Override
+            public OptionalLong get() {
+                return hasValue ? OptionalLong.of(value) : null;
+            }
+
+            static final TerminalOp<Long, OptionalLong> OP_FIND_FIRST = new FindOp<>(true,
+                    StreamShape.LONG_VALUE, OptionalLong.empty(),
+                    OptionalLong::isPresent, FindSink.OfLong::new);
+            static final TerminalOp<Long, OptionalLong> OP_FIND_ANY = new FindOp<>(false,
+                    StreamShape.LONG_VALUE, OptionalLong.empty(),
+                    OptionalLong::isPresent, FindSink.OfLong::new);
+        }
+
+        /** Specialization of {@code FindSink} for double streams */
+        static final class OfDouble extends FindSink<Double, OptionalDouble>
+                implements Sink.OfDouble {
+            @Override
+            public void accept(double value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Double) value);
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return hasValue ? OptionalDouble.of(value) : null;
+            }
+
+            static final TerminalOp<Double, OptionalDouble> OP_FIND_FIRST = new FindOp<>(true,
+                    StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
+                    OptionalDouble::isPresent, FindSink.OfDouble::new);
+            static final TerminalOp<Double, OptionalDouble> OP_FIND_ANY = new FindOp<>(false,
+                    StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
+                    OptionalDouble::isPresent, FindSink.OfDouble::new);
+        }
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing parallel short-circuiting search
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     * @param <O> Result type from the find operation
+     */
+    @SuppressWarnings("serial")
+    private static final class FindTask<P_IN, P_OUT, O>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
+        private final FindOp<P_OUT, O> op;
+        private final boolean mustFindFirst;
+
+        FindTask(FindOp<P_OUT, O> op,
+                 boolean mustFindFirst,
+                 PipelineHelper<P_OUT> helper,
+                 Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.mustFindFirst = mustFindFirst;
+            this.op = op;
+        }
+
+        FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.mustFindFirst = parent.mustFindFirst;
+            this.op = parent.op;
+        }
+
+        @Override
+        protected FindTask<P_IN, P_OUT, O> makeChild(Spliterator<P_IN> spliterator) {
+            return new FindTask<>(this, spliterator);
+        }
+
+        @Override
+        protected O getEmptyResult() {
+            return op.emptyValue;
+        }
+
+        private void foundResult(O answer) {
+            if (isLeftmostNode())
+                shortCircuit(answer);
+            else
+                cancelLaterNodes();
+        }
+
+        @Override
+        protected O doLeaf() {
+            O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
+            if (!mustFindFirst) {
+                if (result != null)
+                    shortCircuit(result);
+                return null;
+            }
+            else {
+                if (result != null) {
+                    foundResult(result);
+                    return result;
+                }
+                else
+                    return null;
+            }
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (mustFindFirst) {
+                    for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
+                         p = child, child = rightChild) {
+                    O result = child.getLocalResult();
+                    if (result != null && op.presentPredicate.test(result)) {
+                        setLocalResult(result);
+                        foundResult(result);
+                        break;
+                    }
+                }
+            }
+            super.onCompletion(caller);
+        }
+    }
+}
+
diff --git a/android-35/java/util/stream/ForEachOps.java b/android-35/java/util/stream/ForEachOps.java
new file mode 100644
index 0000000..69714ca
--- /dev/null
+++ b/android-35/java/util/stream/ForEachOps.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that perform an
+ * action for every element of a stream.  Supported variants include unordered
+ * traversal (elements are provided to the {@code Consumer} as soon as they are
+ * available), and ordered traversal (elements are provided to the
+ * {@code Consumer} in encounter order.)
+ *
+ * <p>Elements are provided to the {@code Consumer} on whatever thread and
+ * whatever order they become available.  For ordered traversals, it is
+ * guaranteed that processing an element <em>happens-before</em> processing
+ * subsequent elements in the encounter order.
+ *
+ * <p>Exceptions occurring as a result of sending an element to the
+ * {@code Consumer} will be relayed to the caller and traversal will be
+ * prematurely terminated.
+ *
+ * @since 1.8
+ */
+final class ForEachOps {
+
+    private ForEachOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a stream.
+     *
+     * @param action the {@code Consumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @param <T> the type of the stream elements
+     * @return the {@code TerminalOp} instance
+     */
+    public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfRef<>(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of an {@code IntStream}.
+     *
+     * @param action the {@code IntConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Integer, Void> makeInt(IntConsumer action,
+                                                    boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfInt(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code LongStream}.
+     *
+     * @param action the {@code LongConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Long, Void> makeLong(LongConsumer action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfLong(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code DoubleStream}.
+     *
+     * @param action the {@code DoubleConsumer} that receives all elements of
+     *        a stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Double, Void> makeDouble(DoubleConsumer action,
+                                                      boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfDouble(action, ordered);
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output to itself as a {@code TerminalSink}.  Elements will be sent in
+     * whatever thread they become available.  If the traversal is unordered,
+     * they will be sent independent of the stream's encounter order.
+     *
+     * <p>This terminal operation is stateless.  For parallel evaluation, each
+     * leaf instance of a {@code ForEachTask} will send elements to the same
+     * {@code TerminalSink} reference that is an instance of this class.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    abstract static class ForEachOp<T>
+            implements TerminalOp<T, Void>, TerminalSink<T, Void> {
+        private final boolean ordered;
+
+        protected ForEachOp(boolean ordered) {
+            this.ordered = ordered;
+        }
+
+        // TerminalOp
+
+        @Override
+        public int getOpFlags() {
+            return ordered ? 0 : StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public <S> Void evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(this, spliterator).get();
+        }
+
+        @Override
+        public <S> Void evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<S> spliterator) {
+            if (ordered)
+                new ForEachOrderedTask<>(helper, spliterator, this).invoke();
+            else
+                new ForEachTask<>(helper, spliterator, helper.wrapSink(this)).invoke();
+            return null;
+        }
+
+        // TerminalSink
+
+        @Override
+        public Void get() {
+            return null;
+        }
+
+        // Implementations
+
+        /** Implementation class for reference streams */
+        static final class OfRef<T> extends ForEachOp<T> {
+            final Consumer<? super T> consumer;
+
+            OfRef(Consumer<? super T> consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public void accept(T t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code IntStream} */
+        static final class OfInt extends ForEachOp<Integer>
+                implements Sink.OfInt {
+            final IntConsumer consumer;
+
+            OfInt(IntConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.INT_VALUE;
+            }
+
+            @Override
+            public void accept(int t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code LongStream} */
+        static final class OfLong extends ForEachOp<Long>
+                implements Sink.OfLong {
+            final LongConsumer consumer;
+
+            OfLong(LongConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.LONG_VALUE;
+            }
+
+            @Override
+            public void accept(long t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code DoubleStream} */
+        static final class OfDouble extends ForEachOp<Double>
+                implements Sink.OfDouble {
+            final DoubleConsumer consumer;
+
+            OfDouble(DoubleConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.DOUBLE_VALUE;
+            }
+
+            @Override
+            public void accept(double t) {
+                consumer.accept(t);
+            }
+        }
+    }
+
+    /** A {@code ForkJoinTask} for performing a parallel for-each operation */
+    @SuppressWarnings("serial")
+    static final class ForEachTask<S, T> extends CountedCompleter<Void> {
+        private Spliterator<S> spliterator;
+        private final Sink<S> sink;
+        private final PipelineHelper<T> helper;
+        private long targetSize;
+
+        ForEachTask(PipelineHelper<T> helper,
+                    Spliterator<S> spliterator,
+                    Sink<S> sink) {
+            super(null);
+            this.sink = sink;
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = 0L;
+        }
+
+        ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.sink = parent.sink;
+            this.targetSize = parent.targetSize;
+            this.helper = parent.helper;
+        }
+
+        // Similar to AbstractTask but doesn't need to track child tasks
+        public void compute() {
+            Spliterator<S> rightSplit = spliterator, leftSplit;
+            long sizeEstimate = rightSplit.estimateSize(), sizeThreshold;
+            if ((sizeThreshold = targetSize) == 0L)
+                targetSize = sizeThreshold = AbstractTask.suggestTargetSize(sizeEstimate);
+            boolean isShortCircuit = StreamOpFlag.SHORT_CIRCUIT.isKnown(helper.getStreamAndOpFlags());
+            boolean forkRight = false;
+            Sink<S> taskSink = sink;
+            ForEachTask<S, T> task = this;
+            while (!isShortCircuit || !taskSink.cancellationRequested()) {
+                if (sizeEstimate <= sizeThreshold ||
+                    (leftSplit = rightSplit.trySplit()) == null) {
+                    task.helper.copyInto(taskSink, rightSplit);
+                    break;
+                }
+                ForEachTask<S, T> leftTask = new ForEachTask<>(task, leftSplit);
+                task.addToPendingCount(1);
+                ForEachTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    taskToFork = task;
+                    task = leftTask;
+                }
+                else {
+                    forkRight = true;
+                    taskToFork = leftTask;
+                }
+                taskToFork.fork();
+                sizeEstimate = rightSplit.estimateSize();
+            }
+            task.spliterator = null;
+            task.propagateCompletion();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel for-each operation
+     * which visits the elements in encounter order
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachOrderedTask<S, T> extends CountedCompleter<Void> {
+        /*
+         * Our goal is to ensure that the elements associated with a task are
+         * processed according to an in-order traversal of the computation tree.
+         * We use completion counts for representing these dependencies, so that
+         * a task does not complete until all the tasks preceding it in this
+         * order complete.  We use the "completion map" to associate the next
+         * task in this order for any left child.  We increase the pending count
+         * of any node on the right side of such a mapping by one to indicate
+         * its dependency, and when a node on the left side of such a mapping
+         * completes, it decrements the pending count of its corresponding right
+         * side.  As the computation tree is expanded by splitting, we must
+         * atomically update the mappings to maintain the invariant that the
+         * completion map maps left children to the next node in the in-order
+         * traversal.
+         *
+         * Take, for example, the following computation tree of tasks:
+         *
+         *       a
+         *      / \
+         *     b   c
+         *    / \ / \
+         *   d  e f  g
+         *
+         * The complete map will contain (not necessarily all at the same time)
+         * the following associations:
+         *
+         *   d -> e
+         *   b -> f
+         *   f -> g
+         *
+         * Tasks e, f, g will have their pending counts increased by 1.
+         *
+         * The following relationships hold:
+         *
+         *   - completion of d "happens-before" e;
+         *   - completion of d and e "happens-before b;
+         *   - completion of b "happens-before" f; and
+         *   - completion of f "happens-before" g
+         *
+         * Thus overall the "happens-before" relationship holds for the
+         * reporting of elements, covered by tasks d, e, f and g, as specified
+         * by the forEachOrdered operation.
+         */
+
+        private final PipelineHelper<T> helper;
+        private Spliterator<S> spliterator;
+        private final long targetSize;
+        private final ConcurrentHashMap<ForEachOrderedTask<S, T>, ForEachOrderedTask<S, T>> completionMap;
+        private final Sink<T> action;
+        private final ForEachOrderedTask<S, T> leftPredecessor;
+        private Node<T> node;
+
+        protected ForEachOrderedTask(PipelineHelper<T> helper,
+                                     Spliterator<S> spliterator,
+                                     Sink<T> action) {
+            super(null);
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            // Size map to avoid concurrent re-sizes
+            this.completionMap = new ConcurrentHashMap<>(Math.max(16, AbstractTask.getLeafTarget() << 1));
+            this.action = action;
+            this.leftPredecessor = null;
+        }
+
+        ForEachOrderedTask(ForEachOrderedTask<S, T> parent,
+                           Spliterator<S> spliterator,
+                           ForEachOrderedTask<S, T> leftPredecessor) {
+            super(parent);
+            this.helper = parent.helper;
+            this.spliterator = spliterator;
+            this.targetSize = parent.targetSize;
+            this.completionMap = parent.completionMap;
+            this.action = parent.action;
+            this.leftPredecessor = leftPredecessor;
+        }
+
+        @Override
+        public final void compute() {
+            doCompute(this);
+        }
+
+        private static <S, T> void doCompute(ForEachOrderedTask<S, T> task) {
+            Spliterator<S> rightSplit = task.spliterator, leftSplit;
+            long sizeThreshold = task.targetSize;
+            boolean forkRight = false;
+            while (rightSplit.estimateSize() > sizeThreshold &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                ForEachOrderedTask<S, T> leftChild =
+                    new ForEachOrderedTask<>(task, leftSplit, task.leftPredecessor);
+                ForEachOrderedTask<S, T> rightChild =
+                    new ForEachOrderedTask<>(task, rightSplit, leftChild);
+
+                // Fork the parent task
+                // Completion of the left and right children "happens-before"
+                // completion of the parent
+                task.addToPendingCount(1);
+                // Completion of the left child "happens-before" completion of
+                // the right child
+                rightChild.addToPendingCount(1);
+                task.completionMap.put(leftChild, rightChild);
+
+                // If task is not on the left spine
+                if (task.leftPredecessor != null) {
+                    /*
+                     * Completion of left-predecessor, or left subtree,
+                     * "happens-before" completion of left-most leaf node of
+                     * right subtree.
+                     * The left child's pending count needs to be updated before
+                     * it is associated in the completion map, otherwise the
+                     * left child can complete prematurely and violate the
+                     * "happens-before" constraint.
+                     */
+                    leftChild.addToPendingCount(1);
+                    // Update association of left-predecessor to left-most
+                    // leaf node of right subtree
+                    if (task.completionMap.replace(task.leftPredecessor, task, leftChild)) {
+                        // If replaced, adjust the pending count of the parent
+                        // to complete when its children complete
+                        task.addToPendingCount(-1);
+                    } else {
+                        // Left-predecessor has already completed, parent's
+                        // pending count is adjusted by left-predecessor;
+                        // left child is ready to complete
+                        leftChild.addToPendingCount(-1);
+                    }
+                }
+
+                ForEachOrderedTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    task = leftChild;
+                    taskToFork = rightChild;
+                }
+                else {
+                    forkRight = true;
+                    task = rightChild;
+                    taskToFork = leftChild;
+                }
+                taskToFork.fork();
+            }
+
+            /*
+             * Task's pending count is either 0 or 1.  If 1 then the completion
+             * map will contain a value that is task, and two calls to
+             * tryComplete are required for completion, one below and one
+             * triggered by the completion of task's left-predecessor in
+             * onCompletion.  Therefore there is no data race within the if
+             * block.
+             */
+            if (task.getPendingCount() > 0) {
+                // Cannot complete just yet so buffer elements into a Node
+                // for use when completion occurs
+                @SuppressWarnings("unchecked")
+                IntFunction<T[]> generator = size -> (T[]) new Object[size];
+                Node.Builder<T> nb = task.helper.makeNodeBuilder(
+                        task.helper.exactOutputSizeIfKnown(rightSplit),
+                        generator);
+                task.node = task.helper.wrapAndCopyInto(nb, rightSplit).build();
+                task.spliterator = null;
+            }
+            task.tryComplete();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (node != null) {
+                // Dump buffered elements from this leaf into the sink
+                node.forEach(action);
+                node = null;
+            }
+            else if (spliterator != null) {
+                // Dump elements output from this leaf's pipeline into the sink
+                helper.wrapAndCopyInto(action, spliterator);
+                spliterator = null;
+            }
+
+            // The completion of this task *and* the dumping of elements
+            // "happens-before" completion of the associated left-most leaf task
+            // of right subtree (if any, which can be this task's right sibling)
+            //
+            ForEachOrderedTask<S, T> leftDescendant = completionMap.remove(this);
+            if (leftDescendant != null)
+                leftDescendant.tryComplete();
+        }
+    }
+}
diff --git a/android-35/java/util/stream/IntPipeline.java b/android-35/java/util/stream/IntPipeline.java
new file mode 100644
index 0000000..8189699
--- /dev/null
+++ b/android-35/java/util/stream/IntPipeline.java
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code int}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class IntPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Integer, IntStream>
+        implements IntStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Supplier<? extends Spliterator<Integer>> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Spliterator<Integer> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source
+     * @param opFlags the operation flags for the new operation
+     */
+    IntPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Integer> to an {@code IntConsumer}, ideally simply
+     * by casting.
+     */
+    private static IntConsumer adapt(Sink<Integer> sink) {
+        if (sink instanceof IntConsumer) {
+            return (IntConsumer) sink;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Sink<Integer> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Integer>} to a {@code Spliterator.OfInt}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfInt, and throws an
+     * exception if this cast is not possible.
+     */
+    private static Spliterator.OfInt adapt(Spliterator<Integer> s) {
+        if (s instanceof Spliterator.OfInt) {
+            return (Spliterator.OfInt) s;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Spliterator<Integer> s)");
+            throw new UnsupportedOperationException("IntStream.adapt(Spliterator<Integer> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Integer> evaluateToNode(PipelineHelper<Integer> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree,
+                                                     IntFunction<Integer[]> generator) {
+        return Nodes.collectInt(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Integer> wrap(PipelineHelper<Integer> ph,
+                                                  Supplier<Spliterator<P_IN>> supplier,
+                                                  boolean isParallel) {
+        return new StreamSpliterators.IntWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfInt lazySpliterator(Supplier<? extends Spliterator<Integer>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfInt((Supplier<Spliterator.OfInt>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final boolean forEachWithCancel(Spliterator<Integer> spliterator, Sink<Integer> sink) {
+        Spliterator.OfInt spl = adapt(spliterator);
+        IntConsumer adaptedSink = adapt(sink);
+        boolean cancelled;
+        do { } while (!(cancelled = sink.cancellationRequested()) && spl.tryAdvance(adaptedSink));
+        return cancelled;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Integer> makeNodeBuilder(long exactSizeIfKnown,
+                                                       IntFunction<Integer[]> generator) {
+        return Nodes.intBuilder(exactSizeIfKnown);
+    }
+
+    private <U> Stream<U> mapToObj(IntFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE, opFlags) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedInt<U>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    // IntStream
+
+    @Override
+    public final PrimitiveIterator.OfInt iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfInt spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from IntStream
+
+    @Override
+    public final LongStream asLongStream() {
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
+            @Override
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((long) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Integer> boxed() {
+        return mapToObj(Integer::valueOf, 0);
+    }
+
+    @Override
+    public final IntStream map(IntUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
+    }
+
+    @Override
+    public final LongStream mapToLong(IntToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    IntConsumer downstreamAsInt = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        try (IntStream result = mapper.apply(t)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsInt);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsInt));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        // If this method is called then an operation within the stream
+                        // pipeline is short-circuiting (see AbstractPipeline.copyInto).
+                        // Note that we cannot differentiate between an upstream or
+                        // downstream operation
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapMulti(IntMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<>(this, StreamShape.INT_VALUE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(int t) {
+                        mapper.accept(t, (IntConsumer) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public IntStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final IntStream filter(IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream peek(IntConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from IntStream
+
+    @Override
+    public final IntStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeInt(this, 0, maxSize);
+    }
+
+    @Override
+    public final IntStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeInt(this, n, -1);
+    }
+
+    @Override
+    public final IntStream takeWhile(IntPredicate predicate) {
+        return WhileOps.makeTakeWhileInt(this, predicate);
+    }
+
+    @Override
+    public final IntStream dropWhile(IntPredicate predicate) {
+        return WhileOps.makeDropWhileInt(this, predicate);
+    }
+
+    @Override
+    public final IntStream sorted() {
+        return SortedOps.makeInt(this);
+    }
+
+    @Override
+    public final IntStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires an int-specific map/set implementation.
+        return boxed().distinct().mapToInt(i -> i);
+    }
+
+    // Terminal ops from IntStream
+
+    @Override
+    public void forEach(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, true));
+    }
+
+    @Override
+    public final int sum() {
+        return reduce(0, Integer::sum);
+    }
+
+    @Override
+    public final OptionalInt min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalInt max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final long count() {
+        return evaluate(ReduceOps.makeIntCounting());
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final IntSummaryStatistics summaryStatistics() {
+        return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
+                       IntSummaryStatistics::combine);
+    }
+
+    @Override
+    public final int reduce(int identity, IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(identity, op));
+    }
+
+    @Override
+    public final OptionalInt reduce(IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjIntConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        Objects.requireNonNull(combiner);
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalInt findFirst() {
+        return evaluate(FindOps.makeInt(true));
+    }
+
+    @Override
+    public final OptionalInt findAny() {
+        return evaluate(FindOps.makeInt(false));
+    }
+
+    @Override
+    public final int[] toArray() {
+        return Nodes.flattenInt((Node.OfInt) evaluateToArrayNode(Integer[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Integer>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Integer> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Integer> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of an IntStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Integer[]> generator);
+    }
+}
diff --git a/android-35/java/util/stream/IntStream.java b/android-35/java/util/stream/IntStream.java
new file mode 100644
index 0000000..74c4814
--- /dev/null
+++ b/android-35/java/util/stream/IntStream.java
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntSupplier;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive int-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code int} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface IntStream extends BaseStream<Integer, IntStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    IntStream filter(IntPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream map(IntUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(IntFunction<? extends U> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(IntToLongFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(IntToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces an
+     *               {@code IntStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    IntStream flatMap(IntFunction<? extends IntStream> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with multiple elements, specifically zero or more elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain IntConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain IntConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMap flatMap} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with an {@code IntConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates an {@code IntStream} from the
+     * internal buffer. Finally, it returns this stream to {@code flatMap}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see Stream#mapMulti Stream.mapMulti
+     * @since 16
+     */
+    default IntStream mapMulti(IntMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMap(e -> {
+            SpinedBuffer.OfInt buffer = new SpinedBuffer.OfInt();
+            mapper.accept(e, buffer);
+            return StreamSupport.intStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     IntStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * <p>In cases where the stream implementation is able to optimize away the
+     * production of some or all the elements (such as with short-circuiting
+     * operations like {@code findFirst}, or in the example described in
+     * {@link #count}), the action will not be invoked for those elements.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    IntStream peek(IntConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    IntStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    IntStream skip(long n);
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the longest
+     * prefix of elements taken from this stream that match the given predicate.
+     * Otherwise returns, if this stream is unordered, a stream consisting of a
+     * subset of elements taken from this stream that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to take any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * takes all elements (the result is the same as the input), or if no
+     * elements of the stream match the given predicate then no elements are
+     * taken (the result is an empty stream).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code takeWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as {@link #generate(IntSupplier)})
+     * or removing the ordering constraint with {@link #unordered()} may result
+     * in significant speedups of {@code takeWhile()} in parallel pipelines, if
+     * the semantics of your situation permit.  If consistency with encounter
+     * order is required, and you are experiencing poor performance or memory
+     * utilization with {@code takeWhile()} in parallel pipelines, switching to
+     * sequential execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default IntStream takeWhile(IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.intStream(
+                new WhileOps.UnorderedWhileSpliterator.OfInt.Taking(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the remaining
+     * elements of this stream after dropping the longest prefix of elements
+     * that match the given predicate.  Otherwise returns, if this stream is
+     * unordered, a stream consisting of the remaining elements of this stream
+     * after dropping a subset of elements that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to drop any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * drops all elements (the result is an empty stream), or if no elements of
+     * the stream match the given predicate then no elements are dropped (the
+     * result is the same as the input).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code dropWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as {@link #generate(IntSupplier)})
+     * or removing the ordering constraint with {@link #unordered()} may result
+     * in significant speedups of {@code dropWhile()} in parallel pipelines, if
+     * the semantics of your situation permit.  If consistency with encounter
+     * order is required, and you are experiencing poor performance or memory
+     * utilization with {@code dropWhile()} in parallel pipelines, switching to
+     * sequential execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default IntStream dropWhile(IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.intStream(
+                new WhileOps.UnorderedWhileSpliterator.OfInt.Dropping(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(IntConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(IntConsumer)
+     */
+    void forEachOrdered(IntConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    int[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     int result = identity;
+     *     for (int element : this stream)
+     *         result = accumulator.applyAsInt(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min and max are all special cases of reduction that can be
+     * expressed using this method.
+     * For example, summing a stream can be expressed as:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    int reduce(int identity, IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalInt} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     int result = null;
+     *     for (int element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsInt(result, element);
+     *     }
+     *     return foundAny ? OptionalInt.of(result) : OptionalInt.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(int, IntBinaryOperator)
+     */
+    OptionalInt reduce(IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (int element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(int, IntBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> the type of the mutable result container
+     * @param supplier a function that creates a new mutable result container.
+     *                 For a parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that must fold an element into a result
+     *                    container.
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that accepts two partial result containers
+     *                    and merges them, which must be compatible with the
+     *                    accumulator function.  The combiner function must fold
+     *                    the elements from the second result container into the
+     *                    first result container.
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjIntConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    int sum();
+
+    /**
+     * Returns an {@code OptionalInt} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the minimum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt min();
+
+    /**
+     * Returns an {@code OptionalInt} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the maximum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @apiNote
+     * An implementation may choose to not execute the stream pipeline (either
+     * sequentially or in parallel) if it is capable of computing the count
+     * directly from the stream source.  In such cases no source elements will
+     * be traversed and no intermediate operations will be evaluated.
+     * Behavioral parameters with side-effects, which are strongly discouraged
+     * except for harmless cases such as debugging, may be affected.  For
+     * example, consider the following stream:
+     * <pre>{@code
+     *     IntStream s = IntStream.of(1, 2, 3, 4);
+     *     long count = s.peek(System.out::println).count();
+     * }</pre>
+     * The number of elements covered by the stream source is known and the
+     * intermediate operation, {@code peek}, does not inject into or remove
+     * elements from the stream (as may be the case for {@code flatMap} or
+     * {@code filter} operations).  Thus the count is 4 and there is no need to
+     * execute the pipeline and, as a side-effect, print out the elements.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns an {@code IntSummaryStatistics} describing various
+     * summary data about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code IntSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    IntSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(IntPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalInt} describing the first element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} describing the first element of this stream,
+     * or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt findFirst();
+
+    /**
+     * Returns an {@link OptionalInt} describing some element of the stream, or
+     * an empty {@code OptionalInt} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalInt} describing some element of this stream, or
+     * an empty {@code OptionalInt} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalInt findAny();
+
+    /**
+     * Returns a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}
+     */
+    LongStream asLongStream();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to an {@code Integer}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to an {@code Integer}
+     */
+    Stream<Integer> boxed();
+
+    @Override
+    IntStream sequential();
+
+    @Override
+    IntStream parallel();
+
+    @Override
+    PrimitiveIterator.OfInt iterator();
+
+    @Override
+    Spliterator.OfInt spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for an {@code IntStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.IntStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code IntStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static IntStream empty() {
+        return StreamSupport.intStream(Spliterators.emptyIntSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static IntStream of(int t) {
+        return StreamSupport.intStream(new Streams.IntStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static IntStream of(int... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code IntStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code IntStream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * <p>The action of applying {@code f} for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying {@code f} for subsequent elements.  For any given
+     * element the action may be performed in whatever thread the library
+     * chooses.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code IntStream}
+     */
+    public static IntStream iterate(final int seed, final IntUnaryOperator f) {
+        Objects.requireNonNull(f);
+        Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            int prev;
+            boolean started;
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+                int t;
+                if (started)
+                    t = f.applyAsInt(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+        };
+        return StreamSupport.intStream(spliterator, false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} produced by iterative
+     * application of the given {@code next} function to an initial element,
+     * conditioned on satisfying the given {@code hasNext} predicate.  The
+     * stream terminates as soon as the {@code hasNext} predicate returns false.
+     *
+     * <p>{@code IntStream.iterate} should produce the same sequence of elements as
+     * produced by the corresponding for-loop:
+     * <pre>{@code
+     *     for (int index=seed; hasNext.test(index); index = next.applyAsInt(index)) {
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * <p>The resulting sequence may be empty if the {@code hasNext} predicate
+     * does not hold on the seed value.  Otherwise the first element will be the
+     * supplied {@code seed} value, the next element (if present) will be the
+     * result of applying the {@code next} function to the {@code seed} value,
+     * and so on iteratively until the {@code hasNext} predicate indicates that
+     * the stream should terminate.
+     *
+     * <p>The action of applying the {@code hasNext} predicate to an element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying the {@code next} function to that element.  The
+     * action of applying the {@code next} function for one element
+     * <i>happens-before</i> the action of applying the {@code hasNext}
+     * predicate for subsequent elements.  For any given element an action may
+     * be performed in whatever thread the library chooses.
+     *
+     * @param seed the initial element
+     * @param hasNext a predicate to apply to elements to determine when the
+     *                stream must terminate.
+     * @param next a function to be applied to the previous element to produce
+     *             a new element
+     * @return a new sequential {@code IntStream}
+     * @since 9
+     */
+    public static IntStream iterate(int seed, IntPredicate hasNext, IntUnaryOperator next) {
+        Objects.requireNonNull(next);
+        Objects.requireNonNull(hasNext);
+        Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            int prev;
+            boolean started, finished;
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return false;
+                int t;
+                if (started)
+                    t = next.applyAsInt(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                if (!hasNext.test(t)) {
+                    finished = true;
+                    return false;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(IntConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return;
+                finished = true;
+                int t = started ? next.applyAsInt(prev) : seed;
+                while (hasNext.test(t)) {
+                    action.accept(t);
+                    t = next.applyAsInt(t);
+                }
+            }
+        };
+        return StreamSupport.intStream(spliterator, false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code IntSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code IntSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code IntStream}
+     */
+    public static IntStream generate(IntSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.intStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfInt(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream range(int startInclusive, int endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream rangeClosed(int startInclusive, int endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * <p>This method operates on the two input streams and binds each stream
+     * to its source.  As a result subsequent modifications to an input stream
+     * source may not be reflected in the concatenated stream result.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowError}.
+     *
+     * @apiNote
+     * To preserve optimization opportunities this method binds each stream to
+     * its source and accepts only two streams as parameters.  For example, the
+     * exact size of the concatenated stream source can be computed if the exact
+     * size of each input stream source is known.
+     * To concatenate more streams without binding, or without nested calls to
+     * this method, try creating a stream of streams and flat-mapping with the
+     * identity function, for example:
+     * <pre>{@code
+     *     IntStream concat = Stream.of(s1, s2, s3, s4).flatMapToInt(s -> s);
+     * }</pre>
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static IntStream concat(IntStream a, IntStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
+                a.spliterator(), b.spliterator());
+        IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for an {@code IntStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see IntStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends IntConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(int t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(int t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        IntStream build();
+    }
+
+    /**
+     * Represents an operation that accepts an {@code int}-valued argument
+     * and an IntConsumer, and returns no result. This functional interface is
+     * used by {@link IntStream#mapMulti(IntMapMultiConsumer) IntStream.mapMulti}
+     * to replace an int value with zero or more int values.
+     *
+     * <p>This is a <a href="../function/package-summary.html">functional interface</a>
+     * whose functional method is {@link #accept(int, IntConsumer)}.
+     *
+     * @see IntStream#mapMulti(IntMapMultiConsumer)
+     *
+     * @since 16
+     */
+    @FunctionalInterface
+    interface IntMapMultiConsumer {
+
+        /**
+         * Replaces the given {@code value} with zero or more values by feeding the mapped
+         * values to the {@code ic} consumer.
+         *
+         * @param value the int value coming from upstream
+         * @param ic an {@code IntConsumer} accepting the mapped values
+         */
+        void accept(int value, IntConsumer ic);
+    }
+}
diff --git a/android-35/java/util/stream/LongPipeline.java b/android-35/java/util/stream/LongPipeline.java
new file mode 100644
index 0000000..abe2b67
--- /dev/null
+++ b/android-35/java/util/stream/LongPipeline.java
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code long}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class LongPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Long, LongStream>
+        implements LongStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Supplier<? extends Spliterator<Long>> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Spliterator<Long> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    LongPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Long> to an {@code LongConsumer}, ideally simply
+     * by casting.
+     */
+    private static LongConsumer adapt(Sink<Long> sink) {
+        if (sink instanceof LongConsumer) {
+            return (LongConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Sink<Long> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Long>} to a {@code Spliterator.OfLong}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfLong, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfLong adapt(Spliterator<Long> s) {
+        if (s instanceof Spliterator.OfLong) {
+            return (Spliterator.OfLong) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Spliterator<Long> s)");
+            throw new UnsupportedOperationException("LongStream.adapt(Spliterator<Long> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Long> evaluateToNode(PipelineHelper<Long> helper,
+                                           Spliterator<P_IN> spliterator,
+                                           boolean flattenTree,
+                                           IntFunction<Long[]> generator) {
+        return Nodes.collectLong(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Long> wrap(PipelineHelper<Long> ph,
+                                        Supplier<Spliterator<P_IN>> supplier,
+                                        boolean isParallel) {
+        return new StreamSpliterators.LongWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfLong lazySpliterator(Supplier<? extends Spliterator<Long>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfLong((Supplier<Spliterator.OfLong>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final boolean forEachWithCancel(Spliterator<Long> spliterator, Sink<Long> sink) {
+        Spliterator.OfLong spl = adapt(spliterator);
+        LongConsumer adaptedSink =  adapt(sink);
+        boolean cancelled;
+        do { } while (!(cancelled = sink.cancellationRequested()) && spl.tryAdvance(adaptedSink));
+        return cancelled;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Long> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Long[]> generator) {
+        return Nodes.longBuilder(exactSizeIfKnown);
+    }
+
+    private <U> Stream<U> mapToObj(LongFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE, opFlags) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedLong<U>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    // LongStream
+
+    @Override
+    public final PrimitiveIterator.OfLong iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfLong spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from LongStream
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Long> boxed() {
+        return mapToObj(Long::valueOf, 0);
+    }
+
+    @Override
+    public final LongStream map(LongUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
+    }
+
+    @Override
+    public final IntStream mapToInt(LongToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedLong<Integer>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    LongConsumer downstreamAsLong = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        try (LongStream result = mapper.apply(t)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsLong);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsLong));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        // If this method is called then an operation within the stream
+                        // pipeline is short-circuiting (see AbstractPipeline.copyInto).
+                        // Note that we cannot differentiate between an upstream or
+                        // downstream operation
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapMulti(LongMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<>(this, StreamShape.LONG_VALUE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(long t) {
+                        mapper.accept(t, (LongConsumer) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public LongStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final LongStream filter(LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream peek(LongConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from LongStream
+
+    @Override
+    public final LongStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeLong(this, 0, maxSize);
+    }
+
+    @Override
+    public final LongStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeLong(this, n, -1);
+    }
+
+    @Override
+    public final LongStream takeWhile(LongPredicate predicate) {
+        return WhileOps.makeTakeWhileLong(this, predicate);
+    }
+
+    @Override
+    public final LongStream dropWhile(LongPredicate predicate) {
+        return WhileOps.makeDropWhileLong(this, predicate);
+    }
+
+    @Override
+    public final LongStream sorted() {
+        return SortedOps.makeLong(this);
+    }
+
+    @Override
+    public final LongStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a long-specific map/set implementation.
+        return boxed().distinct().mapToLong(i -> (long) i);
+    }
+
+    // Terminal ops from LongStream
+
+    @Override
+    public void forEach(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, true));
+    }
+
+    @Override
+    public final long sum() {
+        // use better algorithm to compensate for intermediate overflow?
+        return reduce(0, Long::sum);
+    }
+
+    @Override
+    public final OptionalLong min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalLong max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return evaluate(ReduceOps.makeLongCounting());
+    }
+
+    @Override
+    public final LongSummaryStatistics summaryStatistics() {
+        return collect(LongSummaryStatistics::new, LongSummaryStatistics::accept,
+                       LongSummaryStatistics::combine);
+    }
+
+    @Override
+    public final long reduce(long identity, LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(identity, op));
+    }
+
+    @Override
+    public final OptionalLong reduce(LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjLongConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        Objects.requireNonNull(combiner);
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeLong(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalLong findFirst() {
+        return evaluate(FindOps.makeLong(true));
+    }
+
+    @Override
+    public final OptionalLong findAny() {
+        return evaluate(FindOps.makeLong(false));
+    }
+
+    @Override
+    public final long[] toArray() {
+        return Nodes.flattenLong((Node.OfLong) evaluateToArrayNode(Long[]::new))
+                .asPrimitiveArray();
+    }
+
+
+    //
+
+    /**
+     * Source stage of a LongPipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Long>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Long> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Long> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /** Base class for a stateless intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         * @hide Visible for CTS testing only (OpenJDK8 tests).
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Long[]> generator);
+    }
+}
diff --git a/android-35/java/util/stream/LongStream.java b/android-35/java/util/stream/LongStream.java
new file mode 100644
index 0000000..8e20326
--- /dev/null
+++ b/android-35/java/util/stream/LongStream.java
@@ -0,0 +1,1243 @@
+/*
+ * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongSupplier;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive long-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code long} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     long sum = widgets.stream()
+ *                       .filter(w -> w.getColor() == RED)
+ *                       .mapToLong(w -> w.getWeight())
+ *                       .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface LongStream extends BaseStream<Long, LongStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    LongStream filter(LongPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream map(LongUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(LongFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(LongToIntFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(LongToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code LongStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    LongStream flatMap(LongFunction<? extends LongStream> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with multiple elements, specifically zero or more elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain LongConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain LongConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMap flatMap} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with a {@code LongConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates a {@code LongStream} from the
+     * internal buffer. Finally, it returns this stream to {@code flatMap}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see Stream#mapMulti Stream.mapMulti
+     * @since 16
+     */
+    default LongStream mapMulti(LongMapMultiConsumer mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMap(e -> {
+            SpinedBuffer.OfLong buffer = new SpinedBuffer.OfLong();
+            mapper.accept(e, buffer);
+            return StreamSupport.longStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     LongStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * <p>In cases where the stream implementation is able to optimize away the
+     * production of some or all the elements (such as with short-circuiting
+     * operations like {@code findFirst}, or in the example described in
+     * {@link #count}), the action will not be invoked for those elements.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    LongStream peek(LongConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    LongStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    LongStream skip(long n);
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the longest
+     * prefix of elements taken from this stream that match the given predicate.
+     * Otherwise returns, if this stream is unordered, a stream consisting of a
+     * subset of elements taken from this stream that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to take any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * takes all elements (the result is the same as the input), or if no
+     * elements of the stream match the given predicate then no elements are
+     * taken (the result is an empty stream).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code takeWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as
+     * {@link #generate(LongSupplier)}) or removing the ordering constraint with
+     * {@link #unordered()} may result in significant speedups of
+     * {@code takeWhile()} in parallel pipelines, if the semantics of your
+     * situation permit.  If consistency with encounter order is required, and
+     * you are experiencing poor performance or memory utilization with
+     * {@code takeWhile()} in parallel pipelines, switching to sequential
+     * execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default LongStream takeWhile(LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.longStream(
+                new WhileOps.UnorderedWhileSpliterator.OfLong.Taking(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the remaining
+     * elements of this stream after dropping the longest prefix of elements
+     * that match the given predicate.  Otherwise returns, if this stream is
+     * unordered, a stream consisting of the remaining elements of this stream
+     * after dropping a subset of elements that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to drop any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * drops all elements (the result is an empty stream), or if no elements of
+     * the stream match the given predicate then no elements are dropped (the
+     * result is the same as the input).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code dropWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as
+     * {@link #generate(LongSupplier)}) or removing the ordering constraint with
+     * {@link #unordered()} may result in significant speedups of
+     * {@code dropWhile()} in parallel pipelines, if the semantics of your
+     * situation permit.  If consistency with encounter order is required, and
+     * you are experiencing poor performance or memory utilization with
+     * {@code dropWhile()} in parallel pipelines, switching to sequential
+     * execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default LongStream dropWhile(LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.longStream(
+                new WhileOps.UnorderedWhileSpliterator.OfLong.Dropping(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(LongConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(LongConsumer)
+     */
+    void forEachOrdered(LongConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    long[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     long result = identity;
+     *     for (long element : this stream)
+     *         result = accumulator.applyAsLong(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    long reduce(long identity, LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalLong} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     long result = null;
+     *     for (long element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsLong(result, element);
+     *     }
+     *     return foundAny ? OptionalLong.of(result) : OptionalLong.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(long, LongBinaryOperator)
+     */
+    OptionalLong reduce(LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (long element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(long, LongBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> the type of the mutable result container
+     * @param supplier a function that creates a new mutable result container.
+     *                 For a parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that must fold an element into a result
+     *                    container.
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that accepts two partial result containers
+     *                    and merges them, which must be compatible with the
+     *                    accumulator function.  The combiner function must fold
+     *                    the elements from the second result container into the
+     *                    first result container.
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjLongConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    long sum();
+
+    /**
+     * Returns an {@code OptionalLong} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the minimum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong min();
+
+    /**
+     * Returns an {@code OptionalLong} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the maximum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return map(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @apiNote
+     * An implementation may choose to not execute the stream pipeline (either
+     * sequentially or in parallel) if it is capable of computing the count
+     * directly from the stream source.  In such cases no source elements will
+     * be traversed and no intermediate operations will be evaluated.
+     * Behavioral parameters with side-effects, which are strongly discouraged
+     * except for harmless cases such as debugging, may be affected.  For
+     * example, consider the following stream:
+     * <pre>{@code
+     *     LongStream s = LongStream.of(1, 2, 3, 4);
+     *     long count = s.peek(System.out::println).count();
+     * }</pre>
+     * The number of elements covered by the stream source is known and the
+     * intermediate operation, {@code peek}, does not inject into or remove
+     * elements from the stream (as may be the case for {@code flatMap} or
+     * {@code filter} operations).  Thus the count is 4 and there is no need to
+     * execute the pipeline and, as a side-effect, print out the elements.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    LongSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(LongPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong findFirst();
+
+    /**
+     * Returns an {@link OptionalLong} describing some element of the stream, or
+     * an empty {@code OptionalLong} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalLong} describing some element of this stream,
+     * or an empty {@code OptionalLong} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalLong findAny();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to a {@code Long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to {@code Long}
+     */
+    Stream<Long> boxed();
+
+    @Override
+    LongStream sequential();
+
+    @Override
+    LongStream parallel();
+
+    @Override
+    PrimitiveIterator.OfLong iterator();
+
+    @Override
+    Spliterator.OfLong spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code LongStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.LongStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code LongStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static LongStream empty() {
+        return StreamSupport.longStream(Spliterators.emptyLongSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static LongStream of(long t) {
+        return StreamSupport.longStream(new Streams.LongStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static LongStream of(long... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code LongStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code LongStream} will
+     * be the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * <p>The action of applying {@code f} for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying {@code f} for subsequent elements.  For any given
+     * element the action may be performed in whatever thread the library
+     * chooses.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code LongStream}
+     */
+    public static LongStream iterate(final long seed, final LongUnaryOperator f) {
+        Objects.requireNonNull(f);
+        Spliterator.OfLong spliterator = new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            long prev;
+            boolean started;
+
+            @Override
+            public boolean tryAdvance(LongConsumer action) {
+                Objects.requireNonNull(action);
+                long t;
+                if (started)
+                    t = f.applyAsLong(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+        };
+        return StreamSupport.longStream(spliterator, false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} produced by iterative
+     * application of the given {@code next} function to an initial element,
+     * conditioned on satisfying the given {@code hasNext} predicate.  The
+     * stream terminates as soon as the {@code hasNext} predicate returns false.
+     *
+     * <p>{@code LongStream.iterate} should produce the same sequence of elements as
+     * produced by the corresponding for-loop:
+     * <pre>{@code
+     *     for (long index=seed; hasNext.test(index); index = next.applyAsLong(index)) {
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * <p>The resulting sequence may be empty if the {@code hasNext} predicate
+     * does not hold on the seed value.  Otherwise the first element will be the
+     * supplied {@code seed} value, the next element (if present) will be the
+     * result of applying the {@code next} function to the {@code seed} value,
+     * and so on iteratively until the {@code hasNext} predicate indicates that
+     * the stream should terminate.
+     *
+     * <p>The action of applying the {@code hasNext} predicate to an element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying the {@code next} function to that element.  The
+     * action of applying the {@code next} function for one element
+     * <i>happens-before</i> the action of applying the {@code hasNext}
+     * predicate for subsequent elements.  For any given element an action may
+     * be performed in whatever thread the library chooses.
+     *
+     * @param seed the initial element
+     * @param hasNext a predicate to apply to elements to determine when the
+     *                stream must terminate.
+     * @param next a function to be applied to the previous element to produce
+     *             a new element
+     * @return a new sequential {@code LongStream}
+     * @since 9
+     */
+    public static LongStream iterate(long seed, LongPredicate hasNext, LongUnaryOperator next) {
+        Objects.requireNonNull(next);
+        Objects.requireNonNull(hasNext);
+        Spliterator.OfLong spliterator = new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) {
+            long prev;
+            boolean started, finished;
+
+            @Override
+            public boolean tryAdvance(LongConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return false;
+                long t;
+                if (started)
+                    t = next.applyAsLong(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                if (!hasNext.test(t)) {
+                    finished = true;
+                    return false;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(LongConsumer action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return;
+                finished = true;
+                long t = started ? next.applyAsLong(prev) : seed;
+                while (hasNext.test(t)) {
+                    action.accept(t);
+                    t = next.applyAsLong(t);
+                }
+            }
+        };
+        return StreamSupport.longStream(spliterator, false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code LongSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code LongSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code LongStream}
+     */
+    public static LongStream generate(LongSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.longStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfLong(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream range(long startInclusive, final long endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else if (endExclusive - startInclusive < 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then
+            // the lower range, [Long.MIN_VALUE, 0) will be further split in two
+            long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), range(m, endExclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream rangeClosed(long startInclusive, final long endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else if (endInclusive - startInclusive + 1 <= 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then
+            // the lower range, [Long.MIN_VALUE, 0), and upper range,
+            // [0, Long.MAX_VALUE], will both be further split in two
+            long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), rangeClosed(m, endInclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * <p>This method operates on the two input streams and binds each stream
+     * to its source.  As a result subsequent modifications to an input stream
+     * source may not be reflected in the concatenated stream result.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowError}.
+     *
+     * @apiNote
+     * To preserve optimization opportunities this method binds each stream to
+     * its source and accepts only two streams as parameters.  For example, the
+     * exact size of the concatenated stream source can be computed if the exact
+     * size of each input stream source is known.
+     * To concatenate more streams without binding, or without nested calls to
+     * this method, try creating a stream of streams and flat-mapping with the
+     * identity function, for example:
+     * <pre>{@code
+     *     LongStream concat = Stream.of(s1, s2, s3, s4).flatMapToLong(s -> s);
+     * }</pre>
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static LongStream concat(LongStream a, LongStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
+                a.spliterator(), b.spliterator());
+        LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code LongStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see LongStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends LongConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(long t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(long t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        LongStream build();
+    }
+
+    /**
+     * Represents an operation that accepts a {@code long}-valued argument
+     * and a LongConsumer, and returns no result. This functional interface is
+     * used by {@link LongStream#mapMulti(LongStream.LongMapMultiConsumer) LongStream.mapMulti}
+     * to replace a long value with zero or more long values.
+     *
+     * <p>This is a <a href="../function/package-summary.html">functional interface</a>
+     * whose functional method is {@link #accept(long, LongConsumer)}.
+     *
+     * @see LongStream#mapMulti(LongStream.LongMapMultiConsumer)
+     *
+     * @since 16
+     */
+    @FunctionalInterface
+    interface LongMapMultiConsumer {
+
+        /**
+         * Replaces the given {@code value} with zero or more values by feeding the mapped
+         * values to the {@code lc} consumer.
+         *
+         * @param value the long value coming from upstream
+         * @param lc a {@code LongConsumer} accepting the mapped values
+         */
+        void accept(long value, LongConsumer lc);
+    }
+}
diff --git a/android-35/java/util/stream/MatchOps.java b/android-35/java/util/stream/MatchOps.java
new file mode 100644
index 0000000..568060d
--- /dev/null
+++ b/android-35/java/util/stream/MatchOps.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.DoublePredicate;
+import java.util.function.IntPredicate;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that implement
+ * quantified predicate matching on the elements of a stream. Supported variants
+ * include match-all, match-any, and match-none.
+ *
+ * @since 1.8
+ */
+final class MatchOps {
+
+    private MatchOps() { }
+
+    /**
+     * Enum describing quantified match options -- all match, any match, none
+     * match.
+     */
+    enum MatchKind {
+        /** Do any elements match the predicate? */
+        ANY(true, true),
+
+        /** Do all elements match the predicate? */
+        ALL(false, false),
+
+        /** Do no elements match the predicate? */
+        NONE(true, false);
+
+        private final boolean stopOnPredicateMatches;
+        private final boolean shortCircuitResult;
+
+        private MatchKind(boolean stopOnPredicateMatches,
+                          boolean shortCircuitResult) {
+            this.stopOnPredicateMatches = stopOnPredicateMatches;
+            this.shortCircuitResult = shortCircuitResult;
+        }
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a Stream.
+     *
+     * @param <T> the type of stream elements
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static <T> TerminalOp<T, Boolean> makeRef(Predicate<? super T> predicate,
+            MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<T> {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(T t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.REFERENCE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for an {@code IntStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Integer, Boolean> makeInt(IntPredicate predicate,
+                                                       MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Integer> implements Sink.OfInt {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(int t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.INT_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code LongStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Long, Boolean> makeLong(LongPredicate predicate,
+                                                     MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Long> implements Sink.OfLong {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(long t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.LONG_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code DoubleStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Double, Boolean> makeDouble(DoublePredicate predicate,
+                                                         MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Double> implements Sink.OfDouble {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(double t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.DOUBLE_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that evaluates a predicate on the
+     * elements of a stream and determines whether all, any or none of those
+     * elements match the predicate.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    private static final class MatchOp<T> implements TerminalOp<T, Boolean> {
+        private final StreamShape inputShape;
+        final MatchKind matchKind;
+        final Supplier<BooleanTerminalSink<T>> sinkSupplier;
+
+        /**
+         * Constructs a {@code MatchOp}.
+         *
+         * @param shape the output shape of the stream pipeline
+         * @param matchKind the kind of quantified match (all, any, none)
+         * @param sinkSupplier {@code Supplier} for a {@code Sink} of the
+         *        appropriate shape which implements the matching operation
+         */
+        MatchOp(StreamShape shape,
+                MatchKind matchKind,
+                Supplier<BooleanTerminalSink<T>> sinkSupplier) {
+            this.inputShape = shape;
+            this.matchKind = matchKind;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT | StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <S> Boolean evaluateSequential(PipelineHelper<T> helper,
+                                              Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).getAndClearState();
+        }
+
+        @Override
+        public <S> Boolean evaluateParallel(PipelineHelper<T> helper,
+                                            Spliterator<S> spliterator) {
+            // Approach for parallel implementation:
+            // - Decompose as per usual
+            // - run match on leaf chunks, call result "b"
+            // - if b == matchKind.shortCircuitOn, complete early and return b
+            // - else if we complete normally, return !shortCircuitOn
+
+            return new MatchTask<>(this, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Boolean specific terminal sink to avoid the boxing costs when returning
+     * results.  Subclasses implement the shape-specific functionality.
+     *
+     * @param <T> The output type of the stream pipeline
+     */
+    private abstract static class BooleanTerminalSink<T> implements Sink<T> {
+        boolean stop;
+        boolean value;
+
+        BooleanTerminalSink(MatchKind matchKind) {
+            value = !matchKind.shortCircuitResult;
+        }
+
+        public boolean getAndClearState() {
+            return value;
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return stop;
+        }
+    }
+
+    /**
+     * ForkJoinTask implementation to implement a parallel short-circuiting
+     * quantified match
+     *
+     * @param <P_IN> the type of source elements for the pipeline
+     * @param <P_OUT> the type of output elements for the pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class MatchTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Boolean, MatchTask<P_IN, P_OUT>> {
+        private final MatchOp<P_OUT> op;
+
+        /**
+         * Constructor for root node
+         */
+        MatchTask(MatchOp<P_OUT> op, PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        /**
+         * Constructor for non-root node
+         */
+        MatchTask(MatchTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected MatchTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new MatchTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Boolean doLeaf() {
+            boolean b = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).getAndClearState();
+            if (b == op.matchKind.shortCircuitResult)
+                shortCircuit(b);
+            return null;
+        }
+
+        @Override
+        protected Boolean getEmptyResult() {
+            return !op.matchKind.shortCircuitResult;
+        }
+    }
+}
+
diff --git a/android-35/java/util/stream/Node.java b/android-35/java/util/stream/Node.java
new file mode 100644
index 0000000..17cb679
--- /dev/null
+++ b/android-35/java/util/stream/Node.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An immutable container for describing an ordered sequence of elements of some
+ * type {@code T}.
+ *
+ * <p>A {@code Node} contains a fixed number of elements, which can be accessed
+ * via the {@link #count}, {@link #spliterator}, {@link #forEach},
+ * {@link #asArray}, or {@link #copyInto} methods.  A {@code Node} may have zero
+ * or more child {@code Node}s; if it has no children (accessed via
+ * {@link #getChildCount} and {@link #getChild(int)}, it is considered <em>flat
+ * </em> or a <em>leaf</em>; if it has children, it is considered an
+ * <em>internal</em> node.  The size of an internal node is the sum of sizes of
+ * its children.
+ *
+ * @apiNote
+ * <p>A {@code Node} typically does not store the elements directly, but instead
+ * mediates access to one or more existing (effectively immutable) data
+ * structures such as a {@code Collection}, array, or a set of other
+ * {@code Node}s.  Commonly {@code Node}s are formed into a tree whose shape
+ * corresponds to the computation tree that produced the elements that are
+ * contained in the leaf nodes.  The use of {@code Node} within the stream
+ * framework is largely to avoid copying data unnecessarily during parallel
+ * operations.
+ *
+ * @param <T> the type of elements.
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Node<T> {
+
+    /**
+     * Returns a {@link Spliterator} describing the elements contained in this
+     * {@code Node}.
+     *
+     * @return a {@code Spliterator} describing the elements contained in this
+     *         {@code Node}
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Traverses the elements of this node, and invoke the provided
+     * {@code Consumer} with each element.  Elements are provided in encounter
+     * order if the source for the {@code Node} has a defined encounter order.
+     *
+     * @param consumer a {@code Consumer} that is to be invoked with each
+     *        element in this {@code Node}
+     */
+    void forEach(Consumer<? super T> consumer);
+
+    /**
+     * Returns the number of child nodes of this node.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the number of child nodes
+     */
+    default int getChildCount() {
+        return 0;
+    }
+
+    /**
+     * Retrieves the child {@code Node} at a given index.
+     *
+     * @implSpec The default implementation always throws
+     * {@code IndexOutOfBoundsException}.
+     *
+     * @param i the index to the child node
+     * @return the child node
+     * @throws IndexOutOfBoundsException if the index is less than 0 or greater
+     *         than or equal to the number of child nodes
+     */
+    default Node<T> getChild(int i) {
+        throw new IndexOutOfBoundsException();
+    }
+
+    /**
+     * Return a node describing a subsequence of the elements of this node,
+     * starting at the given inclusive start offset and ending at the given
+     * exclusive end offset.
+     *
+     * @param from The (inclusive) starting offset of elements to include, must
+     *             be in range 0..count().
+     * @param to The (exclusive) end offset of elements to include, must be
+     *           in range 0..count().
+     * @param generator A function to be used to create a new array, if needed,
+     *                  for reference nodes.
+     * @return the truncated node
+     */
+    default Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+        if (from == 0 && to == count())
+            return this;
+        Spliterator<T> spliterator = spliterator();
+        long size = to - from;
+        Node.Builder<T> nodeBuilder = Nodes.builder(size, generator);
+        nodeBuilder.begin(size);
+        for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { }
+        if (to == count()) {
+            spliterator.forEachRemaining(nodeBuilder);
+        } else {
+            for (int i = 0; i < size && spliterator.tryAdvance(nodeBuilder); i++) { }
+        }
+        nodeBuilder.end();
+        return nodeBuilder.build();
+    }
+
+    /**
+     * Provides an array view of the contents of this node.
+     *
+     * <p>Depending on the underlying implementation, this may return a
+     * reference to an internal array rather than a copy.  Since the returned
+     * array may be shared, the returned array should not be modified.  The
+     * {@code generator} function may be consulted to create the array if a new
+     * array needs to be created.
+     *
+     * @param generator a factory function which takes an integer parameter and
+     *        returns a new, empty array of that size and of the appropriate
+     *        array type
+     * @return an array containing the contents of this {@code Node}
+     */
+    T[] asArray(IntFunction<T[]> generator);
+
+    /**
+     * Copies the content of this {@code Node} into an array, starting at a
+     * given offset into the array.  It is the caller's responsibility to ensure
+     * there is sufficient room in the array, otherwise unspecified behaviour
+     * will occur if the array length is less than the number of elements
+     * contained in this node.
+     *
+     * @param array the array into which to copy the contents of this
+     *       {@code Node}
+     * @param offset the starting offset within the array
+     * @throws IndexOutOfBoundsException if copying would cause access of data
+     *         outside array bounds
+     * @throws NullPointerException if {@code array} is {@code null}
+     */
+    void copyInto(T[] array, int offset);
+
+    /**
+     * Gets the {@code StreamShape} associated with this {@code Node}.
+     *
+     * @implSpec The default in {@code Node} returns
+     * {@code StreamShape.REFERENCE}
+     *
+     * @return the stream shape associated with this node
+     */
+    default StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    /**
+     * Returns the number of elements contained in this node.
+     *
+     * @return the number of elements contained in this node
+     */
+    long count();
+
+    /**
+     * A mutable builder for a {@code Node} that implements {@link Sink}, which
+     * builds a flat node containing the elements that have been pushed to it.
+     */
+    interface Builder<T> extends Sink<T> {
+
+        /**
+         * Builds the node.  Should be called after all elements have been
+         * pushed and signalled with an invocation of {@link Sink#end()}.
+         *
+         * @return the resulting {@code Node}
+         */
+        Node<T> build();
+
+        /**
+         * Specialized @{code Node.Builder} for int elements
+         */
+        interface OfInt extends Node.Builder<Integer>, Sink.OfInt {
+            @Override
+            Node.OfInt build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for long elements
+         */
+        interface OfLong extends Node.Builder<Long>, Sink.OfLong {
+            @Override
+            Node.OfLong build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for double elements
+         */
+        interface OfDouble extends Node.Builder<Double>, Sink.OfDouble {
+            @Override
+            Node.OfDouble build();
+        }
+    }
+
+    public interface OfPrimitive<T, T_CONS, T_ARR,
+                                 T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                 T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+            extends Node<T> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @return a {@link Spliterator.OfPrimitive} describing the elements of
+         *         this node
+         */
+        @Override
+        T_SPLITR spliterator();
+
+        /**
+         * Traverses the elements of this node, and invoke the provided
+         * {@code action} with each element.
+         *
+         * @param action a consumer that is to be invoked with each
+         *        element in this {@code Node.OfPrimitive}
+         */
+        @SuppressWarnings("overloads")
+        void forEach(T_CONS action);
+
+        @Override
+        default T_NODE getChild(int i) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        T_NODE truncate(long from, long to, IntFunction<T[]> generator);
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes the generator to create
+         * an instance of a boxed primitive array with a length of
+         * {@link #count()} and then invokes {@link #copyInto(T[], int)} with
+         * that array at an offset of 0.
+         */
+        @Override
+        default T[] asArray(IntFunction<T[]> generator) {
+            if (java.util.stream.Tripwire.ENABLED)
+                java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray");
+
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T[] boxed = generator.apply((int) count());
+            copyInto(boxed, 0);
+            return boxed;
+        }
+
+        /**
+         * Views this node as a primitive array.
+         *
+         * <p>Depending on the underlying implementation this may return a
+         * reference to an internal array rather than a copy.  It is the callers
+         * responsibility to decide if either this node or the array is utilized
+         * as the primary reference for the data.</p>
+         *
+         * @return an array containing the contents of this {@code Node}
+         */
+        T_ARR asPrimitiveArray();
+
+        /**
+         * Creates a new primitive array.
+         *
+         * @param count the length of the primitive array.
+         * @return the new primitive array.
+         */
+        T_ARR newArray(int count);
+
+        /**
+         * Copies the content of this {@code Node} into a primitive array,
+         * starting at a given offset into the array.  It is the caller's
+         * responsibility to ensure there is sufficient room in the array.
+         *
+         * @param array the array into which to copy the contents of this
+         *              {@code Node}
+         * @param offset the starting offset within the array
+         * @throws IndexOutOfBoundsException if copying would cause access of
+         *         data outside array bounds
+         * @throws NullPointerException if {@code array} is {@code null}
+         */
+        void copyInto(T_ARR array, int offset);
+    }
+
+    /**
+     * Specialized {@code Node} for int elements
+     */
+    interface OfInt extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, OfInt> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer a {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code IntConsumer}, it is cast to {@code IntConsumer} so the
+         *        elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfInt.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
+         * obtain an int[] array then and copies the elements from that int[]
+         * array into the boxed Integer[] array.  This is not efficient and it
+         * is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Integer[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Integer[], int)");
+
+            int[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfInt spliterator = spliterator();
+            Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { }
+            if (to == count()) {
+                spliterator.forEachRemaining((IntConsumer) nodeBuilder);
+            } else {
+                for (int i = 0; i < size && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
+            }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default int[] newArray(int count) {
+            return new int[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfInt} returns
+         * {@code StreamShape.INT_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.INT_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for long elements
+     */
+    interface OfLong extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code LongConsumer}, it is cast to {@code LongConsumer} so
+         *        the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a long[] array then and copies the elements from that
+         * long[] array into the boxed Long[] array.  This is not efficient and
+         * it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Long[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Long[], int)");
+
+            long[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfLong spliterator = spliterator();
+            Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { }
+            if (to == count()) {
+                spliterator.forEachRemaining((LongConsumer) nodeBuilder);
+            } else {
+                for (int i = 0; i < size && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
+            }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default long[] newArray(int count) {
+            return new long[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfLong} returns
+         * {@code StreamShape.LONG_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.LONG_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for double elements
+     */
+    interface OfDouble extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code DoubleConsumer}, it is cast to {@code DoubleConsumer}
+         *        so the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        //
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a double[] array then and copies the elements from that
+         * double[] array into the boxed Double[] array.  This is not efficient
+         * and it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Double[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfDouble.copyInto(Double[], int)");
+
+            double[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfDouble spliterator = spliterator();
+            Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { }
+            if (to == count()) {
+                spliterator.forEachRemaining((DoubleConsumer) nodeBuilder);
+            } else {
+                for (int i = 0; i < size && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
+            }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default double[] newArray(int count) {
+            return new double[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec The default in {@code Node.OfDouble} returns
+         * {@code StreamShape.DOUBLE_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.DOUBLE_VALUE;
+        }
+    }
+}
diff --git a/android-35/java/util/stream/Nodes.java b/android-35/java/util/stream/Nodes.java
new file mode 100644
index 0000000..7922624
--- /dev/null
+++ b/android-35/java/util/stream/Nodes.java
@@ -0,0 +1,2235 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+
+/**
+ * Factory methods for constructing implementations of {@link Node} and
+ * {@link Node.Builder} and their primitive specializations.  Fork/Join tasks
+ * for collecting output from a {@link PipelineHelper} to a {@link Node} and
+ * flattening {@link Node}s.
+ *
+ * @since 1.8
+ */
+final class Nodes {
+
+    private Nodes() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * The maximum size of an array that can be allocated.
+     */
+    static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    // IllegalArgumentException messages
+    static final String BAD_SIZE = "Stream size exceeds max array size";
+
+    @SuppressWarnings("rawtypes")
+    private static final Node EMPTY_NODE = new EmptyNode.OfRef();
+    private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt();
+    private static final Node.OfLong EMPTY_LONG_NODE = new EmptyNode.OfLong();
+    private static final Node.OfDouble EMPTY_DOUBLE_NODE = new EmptyNode.OfDouble();
+
+    /**
+     * @return an array generator for an array whose elements are of type T.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> IntFunction<T[]> castingArray() {
+        return size -> (T[]) new Object[size];
+    }
+
+    // General shape-based node creation methods
+
+    /**
+     * Produces an empty node whose count is zero, has no children and no content.
+     *
+     * @param <T> the type of elements of the created node
+     * @param shape the shape of the node to be created
+     * @return an empty node.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> emptyNode(StreamShape shape) {
+        switch (shape) {
+            case REFERENCE:    return (Node<T>) EMPTY_NODE;
+            case INT_VALUE:    return (Node<T>) EMPTY_INT_NODE;
+            case LONG_VALUE:   return (Node<T>) EMPTY_LONG_NODE;
+            case DOUBLE_VALUE: return (Node<T>) EMPTY_DOUBLE_NODE;
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    /**
+     * Produces a concatenated {@link Node} that has two or more children.
+     * <p>The count of the concatenated node is equal to the sum of the count
+     * of each child. Traversal of the concatenated node traverses the content
+     * of each child in encounter order of the list of children. Splitting a
+     * spliterator obtained from the concatenated node preserves the encounter
+     * order of the list of children.
+     *
+     * <p>The result may be a concatenated node, the input sole node if the size
+     * of the list is 1, or an empty node.
+     *
+     * @param <T> the type of elements of the concatenated node
+     * @param shape the shape of the concatenated node to be created
+     * @param left the left input node
+     * @param right the right input node
+     * @return a {@code Node} covering the elements of the input nodes
+     * @throws IllegalStateException if all {@link Node} elements of the list
+     * are an not instance of type supported by this factory.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) {
+        switch (shape) {
+            case REFERENCE:
+                return new ConcNode<>(left, right);
+            case INT_VALUE:
+                return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right);
+            case LONG_VALUE:
+                return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right);
+            case DOUBLE_VALUE:
+                return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    // Reference-based node methods
+
+    /**
+     * Produces a {@link Node} describing an array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param array the array
+     * @return a node holding an array
+     */
+    static <T> Node<T> node(T[] array) {
+        return new ArrayNode<>(array);
+    }
+
+    /**
+     * Produces a {@link Node} describing a {@link Collection}.
+     * <p>
+     * The node will hold a reference to the collection and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param c the collection
+     * @return a node holding a collection
+     */
+    static <T> Node<T> node(Collection<T> c) {
+        return new CollectionNode<>(c);
+    }
+
+    /**
+     * Produces a {@link Node.Builder}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @param generator the array factory
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder(long exactSizeIfKnown, IntFunction<T[]> generator) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new FixedNodeBuilder<>(exactSizeIfKnown, generator)
+               : builder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder}.
+     *
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder() {
+        return new SpinedNodeBuilder<>();
+    }
+
+    // Int nodes
+
+    /**
+     * Produces a {@link Node.OfInt} describing an int[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfInt node(int[] array) {
+        return new IntArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfInt}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new IntFixedNodeBuilder(exactSizeIfKnown)
+               : intBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfInt}.
+     *
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder() {
+        return new IntSpinedNodeBuilder();
+    }
+
+    // Long nodes
+
+    /**
+     * Produces a {@link Node.OfLong} describing a long[] array.
+     * <p>
+     * The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfLong node(final long[] array) {
+        return new LongArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfLong}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new LongFixedNodeBuilder(exactSizeIfKnown)
+               : longBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfLong}.
+     *
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder() {
+        return new LongSpinedNodeBuilder();
+    }
+
+    // Double nodes
+
+    /**
+     * Produces a {@link Node.OfDouble} describing a double[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfDouble node(final double[] array) {
+        return new DoubleArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfDouble}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new DoubleFixedNodeBuilder(exactSizeIfKnown)
+               : doubleBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfDouble}.
+     *
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder() {
+        return new DoubleSpinedNodeBuilder();
+    }
+
+    // Parallel evaluation of pipelines to nodes
+
+    /**
+     * Collect, in parallel, elements output from a pipeline and describe those
+     * elements with a {@link Node}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node} if desired.
+     *
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @param generator the array generator
+     * @return a {@link Node} describing the output elements
+     */
+    public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_OUT> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    boolean flattenTree,
+                                                    IntFunction<P_OUT[]> generator) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            P_OUT[] array = generator.apply((int) size);
+            new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
+            return node(array);
+        } else {
+            Node<P_OUT> node = new CollectorTask.OfRef<>(helper, generator, spliterator).invoke();
+            return flattenTree ? flatten(node, generator) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from an int-valued pipeline and
+     * describe those elements with a {@link Node.OfInt}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfInt} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfInt} describing the output elements
+     */
+    public static <P_IN> Node.OfInt collectInt(PipelineHelper<Integer> helper,
+                                               Spliterator<P_IN> spliterator,
+                                               boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke();
+            return flattenTree ? flattenInt(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from a long-valued pipeline and
+     * describe those elements with a {@link Node.OfLong}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfLong} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfLong} describing the output elements
+     */
+    public static <P_IN> Node.OfLong collectLong(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke();
+            return flattenTree ? flattenLong(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from n double-valued pipeline and
+     * describe those elements with a {@link Node.OfDouble}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfDouble} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfDouble} describing the output elements
+     */
+    public static <P_IN> Node.OfDouble collectDouble(PipelineHelper<Double> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke();
+            return flattenTree ? flattenDouble(node) : node;
+        }
+    }
+
+    // Parallel flattening of nodes
+
+    /**
+     * Flatten, in parallel, a {@link Node}.  A flattened node is one that has
+     * no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, the generator is used to create an array
+     * whose length is {@link Node#count()}.  Then the node tree is traversed
+     * and leaf node elements are placed in the array concurrently by leaf tasks
+     * at the correct offsets.
+     *
+     * @param <T> type of elements contained by the node
+     * @param node the node to flatten
+     * @param generator the array factory used to create array instances
+     * @return a flat {@code Node}
+     */
+    public static <T> Node<T> flatten(Node<T> node, IntFunction<T[]> generator) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            new ToArrayTask.OfRef<>(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfInt}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new int[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfInt}
+     */
+    public static Node.OfInt flattenInt(Node.OfInt node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new ToArrayTask.OfInt(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfLong}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new long[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfLong}
+     */
+    public static Node.OfLong flattenLong(Node.OfLong node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new ToArrayTask.OfLong(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfDouble}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new double[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfDouble}
+     */
+    public static Node.OfDouble flattenDouble(Node.OfDouble node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new ToArrayTask.OfDouble(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    // Implementations
+
+    private abstract static class EmptyNode<T, T_ARR, T_CONS> implements Node<T> {
+        EmptyNode() { }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            return generator.apply(0);
+        }
+
+        public void copyInto(T_ARR array, int offset) { }
+
+        @Override
+        public long count() {
+            return 0;
+        }
+
+        public void forEach(T_CONS consumer) { }
+
+        private static class OfRef<T> extends EmptyNode<T, T[], Consumer<? super T>> {
+            private OfRef() {
+                super();
+            }
+
+            @Override
+            public Spliterator<T> spliterator() {
+                return Spliterators.emptySpliterator();
+            }
+        }
+
+        private static final class OfInt
+                extends EmptyNode<Integer, int[], IntConsumer>
+                implements Node.OfInt {
+
+            OfInt() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return Spliterators.emptyIntSpliterator();
+            }
+
+            @Override
+            public int[] asPrimitiveArray() {
+                return EMPTY_INT_ARRAY;
+            }
+        }
+
+        private static final class OfLong
+                extends EmptyNode<Long, long[], LongConsumer>
+                implements Node.OfLong {
+
+            OfLong() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return Spliterators.emptyLongSpliterator();
+            }
+
+            @Override
+            public long[] asPrimitiveArray() {
+                return EMPTY_LONG_ARRAY;
+            }
+        }
+
+        private static final class OfDouble
+                extends EmptyNode<Double, double[], DoubleConsumer>
+                implements Node.OfDouble {
+
+            OfDouble() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return Spliterators.emptyDoubleSpliterator();
+            }
+
+            @Override
+            public double[] asPrimitiveArray() {
+                return EMPTY_DOUBLE_ARRAY;
+            }
+        }
+    }
+
+    /** Node class for a reference array */
+    private static class ArrayNode<T> implements Node<T> {
+        final T[] array;
+        int curSize;
+
+        @SuppressWarnings("unchecked")
+        ArrayNode(long size, IntFunction<T[]> generator) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = generator.apply((int) size);
+            this.curSize = 0;
+        }
+
+        ArrayNode(T[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public void copyInto(T[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("ArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /** Node class for a Collection */
+    private static final class CollectionNode<T> implements Node<T> {
+        private final Collection<T> c;
+
+        CollectionNode(Collection<T> c) {
+            this.c = c;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return c.stream().spliterator();
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            for (T t : c)
+                array[offset++] = t;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T[] asArray(IntFunction<T[]> generator) {
+            return c.toArray(generator.apply(c.size()));
+        }
+
+        @Override
+        public long count() {
+            return c.size();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            c.forEach(consumer);
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("CollectionNode[%d][%s]", c.size(), c);
+        }
+    }
+
+    /**
+     * Node class for an internal node with two or more children
+     */
+    private abstract static class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> {
+        protected final T_NODE left;
+        protected final T_NODE right;
+        private final long size;
+
+        AbstractConcNode(T_NODE left, T_NODE right) {
+            this.left = left;
+            this.right = right;
+            // The Node count will be required when the Node spliterator is
+            // obtained and it is cheaper to aggressively calculate bottom up
+            // as the tree is built rather than later on from the top down
+            // traversing the tree
+            this.size = left.count() + right.count();
+        }
+
+        @Override
+        public int getChildCount() {
+            return 2;
+        }
+
+        @Override
+        public T_NODE getChild(int i) {
+            if (i == 0) return left;
+            if (i == 1) return right;
+            throw new IndexOutOfBoundsException();
+        }
+
+        @Override
+        public long count() {
+            return size;
+        }
+    }
+
+    static final class ConcNode<T>
+            extends AbstractConcNode<T, Node<T>>
+            implements Node<T> {
+
+        ConcNode(Node<T> left, Node<T> right) {
+            super(left, right);
+        }
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return new Nodes.InternalNodeSpliterator.OfRef<>(this);
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            Objects.requireNonNull(array);
+            left.copyInto(array, offset);
+            // Cast to int is safe since it is the callers responsibility to
+            // ensure that there is sufficient room in the array
+            right.copyInto(array, offset + (int) left.count());
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            long size = count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            copyInto(array, 0);
+            return array;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            left.forEach(consumer);
+            right.forEach(consumer);
+        }
+
+        @Override
+        public Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long leftCount = left.count();
+            if (from >= leftCount)
+                return right.truncate(from - leftCount, to - leftCount, generator);
+            else if (to <= leftCount)
+                return left.truncate(from, to, generator);
+            else {
+                return Nodes.conc(getShape(), left.truncate(from, leftCount, generator),
+                                  right.truncate(0, to - leftCount, generator));
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (count() < 32) {
+                return String.format("ConcNode[%s.%s]", left, right);
+            } else {
+                return String.format("ConcNode[size=%d]", count());
+            }
+        }
+
+        private abstract static class OfPrimitive<E, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>,
+                                                  T_NODE extends Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends AbstractConcNode<E, T_NODE>
+                implements Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE> {
+
+            OfPrimitive(T_NODE left, T_NODE right) {
+                super(left, right);
+            }
+
+            @Override
+            public void forEach(T_CONS consumer) {
+                left.forEach(consumer);
+                right.forEach(consumer);
+            }
+
+            @Override
+            public void copyInto(T_ARR array, int offset) {
+                left.copyInto(array, offset);
+                // Cast to int is safe since it is the callers responsibility to
+                // ensure that there is sufficient room in the array
+                right.copyInto(array, offset + (int) left.count());
+            }
+
+            @Override
+            public T_ARR asPrimitiveArray() {
+                long size = count();
+                if (size >= MAX_ARRAY_SIZE)
+                    throw new IllegalArgumentException(BAD_SIZE);
+                T_ARR array = newArray((int) size);
+                copyInto(array, 0);
+                return array;
+            }
+
+            @Override
+            public String toString() {
+                if (count() < 32)
+                    return String.format("%s[%s.%s]", this.getClass().getName(), left, right);
+                else
+                    return String.format("%s[size=%d]", this.getClass().getName(), count());
+            }
+        }
+
+        static final class OfInt
+                extends ConcNode.OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Node.OfInt {
+
+            OfInt(Node.OfInt left, Node.OfInt right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return new InternalNodeSpliterator.OfInt(this);
+            }
+        }
+
+        static final class OfLong
+                extends ConcNode.OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Node.OfLong {
+
+            OfLong(Node.OfLong left, Node.OfLong right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return new InternalNodeSpliterator.OfLong(this);
+            }
+        }
+
+        static final class OfDouble
+                extends ConcNode.OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Node.OfDouble {
+
+            OfDouble(Node.OfDouble left, Node.OfDouble right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return new InternalNodeSpliterator.OfDouble(this);
+            }
+        }
+    }
+
+    /** Abstract class for spliterator for all internal node classes */
+    private abstract static class InternalNodeSpliterator<T,
+                                                          S extends Spliterator<T>,
+                                                          N extends Node<T>>
+            implements Spliterator<T> {
+        // Node we are pointing to
+        // null if full traversal has occurred
+        N curNode;
+
+        // next child of curNode to consume
+        int curChildIndex;
+
+        // The spliterator of the curNode if that node is last and has no children.
+        // This spliterator will be delegated to for splitting and traversing.
+        // null if curNode has children
+        S lastNodeSpliterator;
+
+        // spliterator used while traversing with tryAdvance
+        // null if no partial traversal has occurred
+        S tryAdvanceSpliterator;
+
+        // node stack used when traversing to search and find leaf nodes
+        // null if no partial traversal has occurred
+        Deque<N> tryAdvanceStack;
+
+        InternalNodeSpliterator(N curNode) {
+            this.curNode = curNode;
+        }
+
+        /**
+         * Initiate a stack containing, in left-to-right order, the child nodes
+         * covered by this spliterator
+         */
+        @SuppressWarnings("unchecked")
+        protected final Deque<N> initStack() {
+            // Bias size to the case where leaf nodes are close to this node
+            // 8 is the minimum initial capacity for the ArrayDeque implementation
+            Deque<N> stack = new ArrayDeque<>(8);
+            for (int i = curNode.getChildCount() - 1; i >= curChildIndex; i--)
+                stack.addFirst((N) curNode.getChild(i));
+            return stack;
+        }
+
+        /**
+         * Depth first search, in left-to-right order, of the node tree, using
+         * an explicit stack, to find the next non-empty leaf node.
+         */
+        @SuppressWarnings("unchecked")
+        protected final N findNextLeafNode(Deque<N> stack) {
+            N n = null;
+            while ((n = stack.pollFirst()) != null) {
+                if (n.getChildCount() == 0) {
+                    if (n.count() > 0)
+                        return n;
+                } else {
+                    for (int i = n.getChildCount() - 1; i >= 0; i--)
+                        stack.addFirst((N) n.getChild(i));
+                }
+            }
+
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected final boolean initTryAdvance() {
+            if (curNode == null)
+                return false;
+
+            if (tryAdvanceSpliterator == null) {
+                if (lastNodeSpliterator == null) {
+                    // Initiate the node stack
+                    tryAdvanceStack = initStack();
+                    N leaf = findNextLeafNode(tryAdvanceStack);
+                    if (leaf != null)
+                        tryAdvanceSpliterator = (S) leaf.spliterator();
+                    else {
+                        // A non-empty leaf node was not found
+                        // No elements to traverse
+                        curNode = null;
+                        return false;
+                    }
+                }
+                else
+                    tryAdvanceSpliterator = lastNodeSpliterator;
+            }
+            return true;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final S trySplit() {
+            if (curNode == null || tryAdvanceSpliterator != null)
+                return null; // Cannot split if fully or partially traversed
+            else if (lastNodeSpliterator != null)
+                return (S) lastNodeSpliterator.trySplit();
+            else if (curChildIndex < curNode.getChildCount() - 1)
+                return (S) curNode.getChild(curChildIndex++).spliterator();
+            else {
+                curNode = (N) curNode.getChild(curChildIndex);
+                if (curNode.getChildCount() == 0) {
+                    lastNodeSpliterator = (S) curNode.spliterator();
+                    return (S) lastNodeSpliterator.trySplit();
+                }
+                else {
+                    curChildIndex = 0;
+                    return (S) curNode.getChild(curChildIndex++).spliterator();
+                }
+            }
+        }
+
+        @Override
+        public final long estimateSize() {
+            if (curNode == null)
+                return 0;
+
+            // Will not reflect the effects of partial traversal.
+            // This is compliant with the specification
+            if (lastNodeSpliterator != null)
+                return lastNodeSpliterator.estimateSize();
+            else {
+                long size = 0;
+                for (int i = curChildIndex; i < curNode.getChildCount(); i++)
+                    size += curNode.getChild(i).count();
+                return size;
+            }
+        }
+
+        @Override
+        public final int characteristics() {
+            return Spliterator.SIZED;
+        }
+
+        private static final class OfRef<T>
+                extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>> {
+
+            OfRef(Node<T> curNode) {
+                super(curNode);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        Node<T> leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<Node<T>> stack = initStack();
+                        Node<T> leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private abstract static class OfPrimitive<T, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                                  N extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, N>>
+                extends InternalNodeSpliterator<T, T_SPLITR, N>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(N cur) {
+                super(cur);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        N leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<N> stack = initStack();
+                        N leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Node.OfInt cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Node.OfLong cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Node.OfDouble cur) {
+                super(cur);
+            }
+        }
+    }
+
+    /**
+     * Fixed-sized builder class for reference nodes
+     */
+    private static final class FixedNodeBuilder<T>
+            extends ArrayNode<T>
+            implements Node.Builder<T> {
+
+        FixedNodeBuilder(long size, IntFunction<T[]> generator) {
+            super(size, generator);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node<T> build() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length)
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(T t) {
+            if (curSize < array.length) {
+                array[curSize++] = t;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+        }
+
+        @Override
+        public String toString() {
+            return String.format("FixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /**
+     * Variable-sized builder class for reference nodes
+     */
+    private static final class SpinedNodeBuilder<T>
+            extends SpinedBuffer<T>
+            implements Node<T>, Node.Builder<T> {
+        private boolean building = false;
+
+        SpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator<T> spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(T t) {
+            assert building : "not building";
+            super.accept(t);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> arrayFactory) {
+            assert !building : "during building";
+            return super.asArray(arrayFactory);
+        }
+
+        @Override
+        public Node<T> build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    //
+
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+    private static final long[] EMPTY_LONG_ARRAY = new long[0];
+    private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+
+    private static class IntArrayNode implements Node.OfInt {
+        final int[] array;
+        int curSize;
+
+        IntArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new int[(int) size];
+            this.curSize = 0;
+        }
+
+        IntArrayNode(int[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(int[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class LongArrayNode implements Node.OfLong {
+        final long[] array;
+        int curSize;
+
+        LongArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new long[(int) size];
+            this.curSize = 0;
+        }
+
+        LongArrayNode(long[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(long[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class DoubleArrayNode implements Node.OfDouble {
+        final double[] array;
+        int curSize;
+
+        DoubleArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new double[(int) size];
+            this.curSize = 0;
+        }
+
+        DoubleArrayNode(double[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(double[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntFixedNodeBuilder
+            extends IntArrayNode
+            implements Node.Builder.OfInt {
+
+        IntFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfInt build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(int i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class LongFixedNodeBuilder
+            extends LongArrayNode
+            implements Node.Builder.OfLong {
+
+        LongFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfLong build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(long i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class DoubleFixedNodeBuilder
+            extends DoubleArrayNode
+            implements Node.Builder.OfDouble {
+
+        DoubleFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(double i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntSpinedNodeBuilder
+            extends SpinedBuffer.OfInt
+            implements Node.OfInt, Node.Builder.OfInt {
+        private boolean building = false;
+
+        IntSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(int i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfInt build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class LongSpinedNodeBuilder
+            extends SpinedBuffer.OfLong
+            implements Node.OfLong, Node.Builder.OfLong {
+        private boolean building = false;
+
+        LongSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(long i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(long[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfLong build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class DoubleSpinedNodeBuilder
+            extends SpinedBuffer.OfDouble
+            implements Node.OfDouble, Node.Builder.OfDouble {
+        private boolean building = false;
+
+        DoubleSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(double i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(double[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    /*
+     * This and subclasses are not intended to be serializable
+     */
+    @SuppressWarnings("serial")
+    private abstract static class SizedCollectorTask<P_IN, P_OUT, T_SINK extends Sink<P_OUT>,
+                                                     K extends SizedCollectorTask<P_IN, P_OUT, T_SINK, K>>
+            extends CountedCompleter<Void>
+            implements Sink<P_OUT> {
+        protected final Spliterator<P_IN> spliterator;
+        protected final PipelineHelper<P_OUT> helper;
+        protected final long targetSize;
+        protected long offset;
+        protected long length;
+        // For Sink implementation
+        protected int index, fence;
+
+        SizedCollectorTask(Spliterator<P_IN> spliterator,
+                           PipelineHelper<P_OUT> helper,
+                           int arrayLength) {
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            this.offset = 0;
+            this.length = arrayLength;
+        }
+
+        SizedCollectorTask(K parent, Spliterator<P_IN> spliterator,
+                           long offset, long length, int arrayLength) {
+            super(parent);
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.targetSize = parent.targetSize;
+            this.offset = offset;
+            this.length = length;
+
+            if (offset < 0 || length < 0 || (offset + length - 1 >= arrayLength)) {
+                throw new IllegalArgumentException(
+                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
+                                      offset, offset, length, arrayLength));
+            }
+        }
+
+        @Override
+        public void compute() {
+            SizedCollectorTask<P_IN, P_OUT, T_SINK, K> task = this;
+            Spliterator<P_IN> rightSplit = spliterator, leftSplit;
+            while (rightSplit.estimateSize() > task.targetSize &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                task.setPendingCount(1);
+                long leftSplitSize = leftSplit.estimateSize();
+                task.makeChild(leftSplit, task.offset, leftSplitSize).fork();
+                task = task.makeChild(rightSplit, task.offset + leftSplitSize,
+                                      task.length - leftSplitSize);
+            }
+
+            assert task.offset + task.length < MAX_ARRAY_SIZE;
+            @SuppressWarnings("unchecked")
+            T_SINK sink = (T_SINK) task;
+            task.helper.wrapAndCopyInto(sink, rightSplit);
+            task.propagateCompletion();
+        }
+
+        abstract K makeChild(Spliterator<P_IN> spliterator, long offset, long size);
+
+        @Override
+        public void begin(long size) {
+            if (size > length)
+                throw new IllegalStateException("size passed to Sink.begin exceeds array length");
+            // Casts to int are safe since absolute size is verified to be within
+            // bounds when the root concrete SizedCollectorTask is constructed
+            // with the shared array
+            index = (int) offset;
+            fence = index + (int) length;
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfRef<P_IN, P_OUT>
+                extends SizedCollectorTask<P_IN, P_OUT, Sink<P_OUT>, OfRef<P_IN, P_OUT>>
+                implements Sink<P_OUT> {
+            private final P_OUT[] array;
+
+            OfRef(Spliterator<P_IN> spliterator, PipelineHelper<P_OUT> helper, P_OUT[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfRef(OfRef<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator,
+                                         long offset, long size) {
+                return new OfRef<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(P_OUT value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfInt<P_IN>
+                extends SizedCollectorTask<P_IN, Integer, Sink.OfInt, OfInt<P_IN>>
+                implements Sink.OfInt {
+            private final int[] array;
+
+            OfInt(Spliterator<P_IN> spliterator, PipelineHelper<Integer> helper, int[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfInt(SizedCollectorTask.OfInt<P_IN> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfInt<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                     long offset, long size) {
+                return new SizedCollectorTask.OfInt<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(int value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfLong<P_IN>
+                extends SizedCollectorTask<P_IN, Long, Sink.OfLong, OfLong<P_IN>>
+                implements Sink.OfLong {
+            private final long[] array;
+
+            OfLong(Spliterator<P_IN> spliterator, PipelineHelper<Long> helper, long[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfLong(SizedCollectorTask.OfLong<P_IN> parent, Spliterator<P_IN> spliterator,
+                   long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfLong<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                      long offset, long size) {
+                return new SizedCollectorTask.OfLong<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(long value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfDouble<P_IN>
+                extends SizedCollectorTask<P_IN, Double, Sink.OfDouble, OfDouble<P_IN>>
+                implements Sink.OfDouble {
+            private final double[] array;
+
+            OfDouble(Spliterator<P_IN> spliterator, PipelineHelper<Double> helper, double[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfDouble(SizedCollectorTask.OfDouble<P_IN> parent, Spliterator<P_IN> spliterator,
+                     long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfDouble<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                        long offset, long size) {
+                return new SizedCollectorTask.OfDouble<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(double value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private abstract static class ToArrayTask<T, T_NODE extends Node<T>,
+                                              K extends ToArrayTask<T, T_NODE, K>>
+            extends CountedCompleter<Void> {
+        protected final T_NODE node;
+        protected final int offset;
+
+        ToArrayTask(T_NODE node, int offset) {
+            this.node = node;
+            this.offset = offset;
+        }
+
+        ToArrayTask(K parent, T_NODE node, int offset) {
+            super(parent);
+            this.node = node;
+            this.offset = offset;
+        }
+
+        abstract void copyNodeToArray();
+
+        abstract K makeChild(int childIndex, int offset);
+
+        @Override
+        public void compute() {
+            ToArrayTask<T, T_NODE, K> task = this;
+            while (true) {
+                if (task.node.getChildCount() == 0) {
+                    task.copyNodeToArray();
+                    task.propagateCompletion();
+                    return;
+                }
+                else {
+                    task.setPendingCount(task.node.getChildCount() - 1);
+
+                    int size = 0;
+                    int i = 0;
+                    for (;i < task.node.getChildCount() - 1; i++) {
+                        K leftTask = task.makeChild(i, task.offset + size);
+                        size += leftTask.node.count();
+                        leftTask.fork();
+                    }
+                    task = task.makeChild(i, task.offset + size);
+                }
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<T>
+                extends ToArrayTask<T, Node<T>, OfRef<T>> {
+            private final T[] array;
+
+            private OfRef(Node<T> node, T[] array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfRef(OfRef<T> parent, Node<T> node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<T> makeChild(int childIndex, int offset) {
+                return new OfRef<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static class OfPrimitive<T, T_CONS, T_ARR,
+                                         T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                         T_NODE extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends ToArrayTask<T, T_NODE, OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> {
+            private final T_ARR array;
+
+            private OfPrimitive(T_NODE node, T_ARR array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfPrimitive(OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> parent, T_NODE node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) {
+                return new OfPrimitive<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> {
+            private OfInt(Node.OfInt node, int[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> {
+            private OfLong(Node.OfLong node, long[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> {
+            private OfDouble(Node.OfDouble node, double[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class CollectorTask<P_IN, P_OUT, T_NODE extends Node<P_OUT>, T_BUILDER extends Node.Builder<P_OUT>>
+            extends AbstractTask<P_IN, P_OUT, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> {
+        protected final PipelineHelper<P_OUT> helper;
+        protected final LongFunction<T_BUILDER> builderFactory;
+        protected final BinaryOperator<T_NODE> concFactory;
+
+        CollectorTask(PipelineHelper<P_OUT> helper,
+                      Spliterator<P_IN> spliterator,
+                      LongFunction<T_BUILDER> builderFactory,
+                      BinaryOperator<T_NODE> concFactory) {
+            super(helper, spliterator);
+            this.helper = helper;
+            this.builderFactory = builderFactory;
+            this.concFactory = concFactory;
+        }
+
+        CollectorTask(CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> parent,
+                      Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+            builderFactory = parent.builderFactory;
+            concFactory = parent.concFactory;
+        }
+
+        @Override
+        protected CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> makeChild(Spliterator<P_IN> spliterator) {
+            return new CollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        protected T_NODE doLeaf() {
+            T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator));
+            return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf())
+                setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult()));
+            super.onCompletion(caller);
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<P_IN, P_OUT>
+                extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> {
+            OfRef(PipelineHelper<P_OUT> helper,
+                  IntFunction<P_OUT[]> generator,
+                  Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, s -> builder(s, generator), ConcNode::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt<P_IN>
+                extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> {
+            OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong<P_IN>
+                extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> {
+            OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble<P_IN>
+                extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> {
+            OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new);
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/stream/PipelineHelper.java b/android-35/java/util/stream/PipelineHelper.java
new file mode 100644
index 0000000..05358b8
--- /dev/null
+++ b/android-35/java/util/stream/PipelineHelper.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * Helper class for executing <a href="package-summary.html#StreamOps">
+ * stream pipelines</a>, capturing all of the information about a stream
+ * pipeline (output shape, intermediate operations, stream flags, parallelism,
+ * etc) in one place.
+ *
+ * <p>
+ * A {@code PipelineHelper} describes the initial segment of a stream pipeline,
+ * including its source, intermediate operations, and may additionally
+ * incorporate information about the terminal (or stateful) operation which
+ * follows the last intermediate operation described by this
+ * {@code PipelineHelper}. The {@code PipelineHelper} is passed to the
+ * {@link TerminalOp#evaluateParallel(PipelineHelper, java.util.Spliterator)},
+ * {@link TerminalOp#evaluateSequential(PipelineHelper, java.util.Spliterator)},
+ * and {@link AbstractPipeline#opEvaluateParallel(PipelineHelper, java.util.Spliterator,
+ * java.util.function.IntFunction)}, methods, which can use the
+ * {@code PipelineHelper} to access information about the pipeline such as
+ * head shape, stream flags, and size, and use the helper methods
+ * such as {@link #wrapAndCopyInto(Sink, Spliterator)},
+ * {@link #copyInto(Sink, Spliterator)}, and {@link #wrapSink(Sink)} to execute
+ * pipeline operations.
+ *
+ * @param <P_OUT> type of output elements from the pipeline
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class PipelineHelper<P_OUT> {
+
+    /**
+     * Gets the stream shape for the source of the pipeline segment.
+     *
+     * @return the stream shape for the source of the pipeline segment.
+     */
+    abstract StreamShape getSourceShape();
+
+    /**
+     * Gets the combined stream and operation flags for the output of the described
+     * pipeline.  This will incorporate stream flags from the stream source, all
+     * the intermediate operations and the terminal operation.
+     *
+     * @return the combined stream and operation flags
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract int getStreamAndOpFlags();
+
+    /**
+     * Returns the exact output size of the portion of the output resulting from
+     * applying the pipeline stages described by this {@code PipelineHelper} to
+     * the portion of the input described by the provided
+     * {@code Spliterator}, if known.  If not known or known infinite, will
+     * return {@code -1}.
+     *
+     * @apiNote
+     * The exact output size is known if the {@code Spliterator} has the
+     * {@code SIZED} characteristic, and the operation flags
+     * {@link StreamOpFlag#SIZED} is known on the combined stream and operation
+     * flags. The exact output size may differ from spliterator size,
+     * if pipeline contains a slice operation.
+     *
+     * @param spliterator the spliterator describing the relevant portion of the
+     *        source data
+     * @return the exact size if known, or -1 if infinite or unknown
+     */
+    abstract<P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator);
+
+    /**
+     * Applies the pipeline stages described by this {@code PipelineHelper} to
+     * the provided {@code Spliterator} and send the results to the provided
+     * {@code Sink}.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     copyInto(wrapSink(sink), spliterator);
+     * }</pre>
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @param spliterator the spliterator describing the source input to process
+     */
+    abstract<P_IN, S extends Sink<P_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}.  If the stream pipeline is known to have short-circuiting
+     * stages in it (see {@link StreamOpFlag#SHORT_CIRCUIT}), the
+     * {@link Sink#cancellationRequested()} is checked after each
+     * element, stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     */
+    abstract<P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}, checking {@link Sink#cancellationRequested()} after each
+     * element, and stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed or if
+     * cancellation is requested.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     * @return true if the cancellation was requested
+     */
+    abstract <P_IN> boolean copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Takes a {@code Sink} that accepts elements of the output type of the
+     * {@code PipelineHelper}, and wrap it with a {@code Sink} that accepts
+     * elements of the input type and implements all the intermediate operations
+     * described by this {@code PipelineHelper}, delivering the result into the
+     * provided {@code Sink}.
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @return a {@code Sink} that implements the pipeline stages and sends
+     *         results to the provided {@code Sink}
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Sink<P_IN> wrapSink(Sink<P_OUT> sink);
+
+    /**
+     *
+     * @param spliterator
+     * @param <P_IN>
+     * @return
+     */
+    abstract<P_IN> Spliterator<P_OUT> wrapSpliterator(Spliterator<P_IN> spliterator);
+
+    /**
+     * Constructs a @{link Node.Builder} compatible with the output shape of
+     * this {@code PipelineHelper}.
+     *
+     * @param exactSizeIfKnown if >=0 then a builder will be created that has a
+     *        fixed capacity of exactly sizeIfKnown elements; if < 0 then the
+     *        builder has variable capacity.  A fixed capacity builder will fail
+     *        if an element is added after the builder has reached capacity.
+     * @param generator a factory function for array instances
+     * @return a {@code Node.Builder} compatible with the output shape of this
+     *         {@code PipelineHelper}
+     */
+    abstract Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                 IntFunction<P_OUT[]> generator);
+
+    /**
+     * Collects all output elements resulting from applying the pipeline stages
+     * to the source {@code Spliterator} into a {@code Node}.
+     *
+     * @implNote
+     * If the pipeline has no intermediate operations and the source is backed
+     * by a {@code Node} then that {@code Node} will be returned (or flattened
+     * and then returned). This reduces copying for a pipeline consisting of a
+     * stateful operation followed by a terminal operation that returns an
+     * array, such as:
+     * <pre>{@code
+     *     stream.sorted().toArray();
+     * }</pre>
+     *
+     * @param spliterator the source {@code Spliterator}
+     * @param flatten if true and the pipeline is a parallel pipeline then the
+     *        {@code Node} returned will contain no children, otherwise the
+     *        {@code Node} may represent the root in a tree that reflects the
+     *        shape of the computation tree.
+     * @param generator a factory function for array instances
+     * @return the {@code Node} containing all output elements
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Node<P_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                        boolean flatten,
+                                        IntFunction<P_OUT[]> generator);
+}
diff --git a/android-35/java/util/stream/ReduceOps.java b/android-35/java/util/stream/ReduceOps.java
new file mode 100644
index 0000000..64c94ef
--- /dev/null
+++ b/android-35/java/util/stream/ReduceOps.java
@@ -0,0 +1,974 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.ObjIntConsumer;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that implement
+ * reductions.
+ *
+ * @since 1.8
+ */
+final class ReduceOps {
+
+    private ReduceOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the result
+     * @param seed the identity element for the reduction
+     * @param reducer the accumulating function that incorporates an additional
+     *        input element into the result
+     * @param combiner the combining function that combines two intermediate
+     *        results
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, U> TerminalOp<T, U>
+    makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {
+        Objects.requireNonNull(reducer);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<U> implements AccumulatingSink<T, U, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seed;
+            }
+
+            @Override
+            public void accept(T t) {
+                state = reducer.apply(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, U, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values producing an optional reference result.
+     *
+     * @param <T> The type of the input elements, and the type of the result
+     * @param operator The reducing function
+     * @return A {@code TerminalOp} implementing the reduction
+     */
+    public static <T> TerminalOp<T, Optional<T>>
+    makeRef(BinaryOperator<T> operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<T, Optional<T>, ReducingSink> {
+            private boolean empty;
+            private T state;
+
+            public void begin(long size) {
+                empty = true;
+                state = null;
+            }
+
+            @Override
+            public void accept(T t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                } else {
+                    state = operator.apply(state, t);
+                }
+            }
+
+            @Override
+            public Optional<T> get() {
+                return empty ? Optional.empty() : Optional.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<T, Optional<T>, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <I> the type of the intermediate reduction result
+     * @param collector a {@code Collector} defining the reduction
+     * @return a {@code ReduceOp} implementing the reduction
+     */
+    public static <T, I> TerminalOp<T, I>
+    makeRef(Collector<? super T, I, ?> collector) {
+        Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
+        BiConsumer<I, ? super T> accumulator = collector.accumulator();
+        BinaryOperator<I> combiner = collector.combiner();
+        class ReducingSink extends Box<I>
+                implements AccumulatingSink<T, I, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+
+            @Override
+            public int getOpFlags() {
+                return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
+                       ? StreamOpFlag.NOT_ORDERED
+                       : 0;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <R> the type of the result
+     * @param seedFactory a factory to produce a new base accumulator
+     * @param accumulator a function to incorporate an element into an
+     *        accumulator
+     * @param reducer a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, R> TerminalOp<T, R>
+    makeRef(Supplier<R> seedFactory,
+            BiConsumer<R, ? super T> accumulator,
+            BiConsumer<R,R> reducer) {
+        Objects.requireNonNull(seedFactory);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(reducer);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<T, R, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seedFactory.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                reducer.accept(state, other.state);
+            }
+        }
+        return new ReduceOp<T, R, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that counts the number of stream
+     * elements.  If the size of the pipeline is known then count is the size
+     * and there is no need to evaluate the pipeline.  If the size of the
+     * pipeline is non known then count is produced, via reduction, using a
+     * {@link CountingSink}.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code TerminalOp} implementing the counting
+     */
+    public static <T> TerminalOp<T, Long>
+    makeRefCounting() {
+        return new ReduceOp<T, Long, CountingSink<T>>(StreamShape.REFERENCE) {
+            @Override
+            public CountingSink<T> makeSink() { return new CountingSink.OfRef<>(); }
+
+            @Override
+            public <P_IN> Long evaluateSequential(PipelineHelper<T> helper,
+                                                  Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateSequential(helper, spliterator);
+            }
+
+            @Override
+            public <P_IN> Long evaluateParallel(PipelineHelper<T> helper,
+                                                Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateParallel(helper, spliterator);
+            }
+
+            @Override
+            public int getOpFlags() {
+                return StreamOpFlag.NOT_ORDERED;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, Integer>
+    makeInt(int identity, IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, Integer, ReducingSink>, Sink.OfInt {
+            private int state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(int t) {
+                state = operator.applyAsInt(state, t);
+            }
+
+            @Override
+            public Integer get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, Integer, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values, producing an optional integer result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, OptionalInt>
+    makeInt(IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, OptionalInt, ReducingSink>, Sink.OfInt {
+            private boolean empty;
+            private int state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(int t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsInt(state, t);
+                }
+            }
+
+            @Override
+            public OptionalInt get() {
+                return empty ? OptionalInt.empty() : OptionalInt.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, OptionalInt, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code int} values.
+     *
+     * @param <R> The type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return A {@code ReduceOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Integer, R>
+    makeInt(Supplier<R> supplier,
+            ObjIntConsumer<R> accumulator,
+            BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Integer, R, ReducingSink>, Sink.OfInt {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(int t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Integer, R, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that counts the number of stream
+     * elements.  If the size of the pipeline is known then count is the size
+     * and there is no need to evaluate the pipeline.  If the size of the
+     * pipeline is non known then count is produced, via reduction, using a
+     * {@link CountingSink}.
+     *
+     * @return a {@code TerminalOp} implementing the counting
+     */
+    public static TerminalOp<Integer, Long>
+    makeIntCounting() {
+        return new ReduceOp<Integer, Long, CountingSink<Integer>>(StreamShape.INT_VALUE) {
+            @Override
+            public CountingSink<Integer> makeSink() { return new CountingSink.OfInt(); }
+
+            @Override
+            public <P_IN> Long evaluateSequential(PipelineHelper<Integer> helper,
+                                                  Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateSequential(helper, spliterator);
+            }
+
+            @Override
+            public <P_IN> Long evaluateParallel(PipelineHelper<Integer> helper,
+                                                Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateParallel(helper, spliterator);
+            }
+
+            @Override
+            public int getOpFlags() {
+                return StreamOpFlag.NOT_ORDERED;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, Long>
+    makeLong(long identity, LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, Long, ReducingSink>, Sink.OfLong {
+            private long state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(long t) {
+                state = operator.applyAsLong(state, t);
+            }
+
+            @Override
+            public Long get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, Long, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values, producing an optional long result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, OptionalLong>
+    makeLong(LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, OptionalLong, ReducingSink>, Sink.OfLong {
+            private boolean empty;
+            private long state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(long t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsLong(state, t);
+                }
+            }
+
+            @Override
+            public OptionalLong get() {
+                return empty ? OptionalLong.empty() : OptionalLong.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, OptionalLong, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code long} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Long, R>
+    makeLong(Supplier<R> supplier,
+             ObjLongConsumer<R> accumulator,
+             BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Long, R, ReducingSink>, Sink.OfLong {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(long t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Long, R, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that counts the number of stream
+     * elements.  If the size of the pipeline is known then count is the size
+     * and there is no need to evaluate the pipeline.  If the size of the
+     * pipeline is non known then count is produced, via reduction, using a
+     * {@link CountingSink}.
+     *
+     * @return a {@code TerminalOp} implementing the counting
+     */
+    public static TerminalOp<Long, Long>
+    makeLongCounting() {
+        return new ReduceOp<Long, Long, CountingSink<Long>>(StreamShape.LONG_VALUE) {
+            @Override
+            public CountingSink<Long> makeSink() { return new CountingSink.OfLong(); }
+
+            @Override
+            public <P_IN> Long evaluateSequential(PipelineHelper<Long> helper,
+                                                  Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateSequential(helper, spliterator);
+            }
+
+            @Override
+            public <P_IN> Long evaluateParallel(PipelineHelper<Long> helper,
+                                                Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateParallel(helper, spliterator);
+            }
+
+            @Override
+            public int getOpFlags() {
+                return StreamOpFlag.NOT_ORDERED;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, Double>
+    makeDouble(double identity, DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, Double, ReducingSink>, Sink.OfDouble {
+            private double state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(double t) {
+                state = operator.applyAsDouble(state, t);
+            }
+
+            @Override
+            public Double get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, Double, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values, producing an optional double result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, OptionalDouble>
+    makeDouble(DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, OptionalDouble, ReducingSink>, Sink.OfDouble {
+            private boolean empty;
+            private double state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(double t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsDouble(state, t);
+                }
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return empty ? OptionalDouble.empty() : OptionalDouble.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, OptionalDouble, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code double} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Double, R>
+    makeDouble(Supplier<R> supplier,
+               ObjDoubleConsumer<R> accumulator,
+               BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Double, R, ReducingSink>, Sink.OfDouble {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(double t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Double, R, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that counts the number of stream
+     * elements.  If the size of the pipeline is known then count is the size
+     * and there is no need to evaluate the pipeline.  If the size of the
+     * pipeline is non known then count is produced, via reduction, using a
+     * {@link CountingSink}.
+     *
+     * @return a {@code TerminalOp} implementing the counting
+     */
+    public static TerminalOp<Double, Long>
+    makeDoubleCounting() {
+        return new ReduceOp<Double, Long, CountingSink<Double>>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public CountingSink<Double> makeSink() { return new CountingSink.OfDouble(); }
+
+            @Override
+            public <P_IN> Long evaluateSequential(PipelineHelper<Double> helper,
+                                                  Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateSequential(helper, spliterator);
+            }
+
+            @Override
+            public <P_IN> Long evaluateParallel(PipelineHelper<Double> helper,
+                                                Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size != -1)
+                    return size;
+                return super.evaluateParallel(helper, spliterator);
+            }
+
+            @Override
+            public int getOpFlags() {
+                return StreamOpFlag.NOT_ORDERED;
+            }
+        };
+    }
+
+    /**
+     * A sink that counts elements
+     */
+    abstract static class CountingSink<T>
+            extends Box<Long>
+            implements AccumulatingSink<T, Long, CountingSink<T>> {
+        long count;
+
+        @Override
+        public void begin(long size) {
+            count = 0L;
+        }
+
+        @Override
+        public Long get() {
+            return count;
+        }
+
+        @Override
+        public void combine(CountingSink<T> other) {
+            count += other.count;
+        }
+
+        static final class OfRef<T> extends CountingSink<T> {
+            @Override
+            public void accept(T t) {
+                count++;
+            }
+        }
+
+        static final class OfInt extends CountingSink<Integer> implements Sink.OfInt {
+            @Override
+            public void accept(int t) {
+                count++;
+            }
+        }
+
+        static final class OfLong extends CountingSink<Long> implements Sink.OfLong {
+            @Override
+            public void accept(long t) {
+                count++;
+            }
+        }
+
+        static final class OfDouble extends CountingSink<Double> implements Sink.OfDouble {
+            @Override
+            public void accept(double t) {
+                count++;
+            }
+        }
+    }
+
+    /**
+     * A type of {@code TerminalSink} that implements an associative reducing
+     * operation on elements of type {@code T} and producing a result of type
+     * {@code R}.
+     *
+     * @param <T> the type of input element to the combining operation
+     * @param <R> the result type
+     * @param <K> the type of the {@code AccumulatingSink}.
+     */
+    private interface AccumulatingSink<T, R, K extends AccumulatingSink<T, R, K>>
+            extends TerminalSink<T, R> {
+        void combine(K other);
+    }
+
+    /**
+     * State box for a single state element, used as a base class for
+     * {@code AccumulatingSink} instances
+     *
+     * @param <U> The type of the state element
+     */
+    private abstract static class Box<U> {
+        U state;
+
+        Box() {} // Avoid creation of special accessor
+
+        public U get() {
+            return state;
+        }
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output into an {@code AccumulatingSink}, which performs a reduce
+     * operation. The {@code AccumulatingSink} must represent an associative
+     * reducing operation.
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <R> the result type of the reducing operation
+     * @param <S> the type of the {@code AccumulatingSink}
+     */
+    private abstract static class ReduceOp<T, R, S extends AccumulatingSink<T, R, S>>
+            implements TerminalOp<T, R> {
+        private final StreamShape inputShape;
+
+        /**
+         * Create a {@code ReduceOp} of the specified stream shape which uses
+         * the specified {@code Supplier} to create accumulating sinks.
+         *
+         * @param shape The shape of the stream pipeline
+         */
+        ReduceOp(StreamShape shape) {
+            inputShape = shape;
+        }
+
+        public abstract S makeSink();
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <P_IN> R evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<P_IN> spliterator) {
+            return helper.wrapAndCopyInto(makeSink(), spliterator).get();
+        }
+
+        @Override
+        public <P_IN> R evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, helper, spliterator).invoke().get();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel reduce operation.
+     */
+    @SuppressWarnings("serial")
+    private static final class ReduceTask<P_IN, P_OUT, R,
+                                          S extends AccumulatingSink<P_OUT, R, S>>
+            extends AbstractTask<P_IN, P_OUT, S, ReduceTask<P_IN, P_OUT, R, S>> {
+        private final ReduceOp<P_OUT, R, S> op;
+
+        ReduceTask(ReduceOp<P_OUT, R, S> op,
+                   PipelineHelper<P_OUT> helper,
+                   Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        ReduceTask(ReduceTask<P_IN, P_OUT, R, S> parent,
+                   Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected ReduceTask<P_IN, P_OUT, R, S> makeChild(Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected S doLeaf() {
+            return helper.wrapAndCopyInto(op.makeSink(), spliterator);
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                S leftResult = leftChild.getLocalResult();
+                leftResult.combine(rightChild.getLocalResult());
+                setLocalResult(leftResult);
+            }
+            // GC spliterator, left and right child
+            super.onCompletion(caller);
+        }
+    }
+}
diff --git a/android-35/java/util/stream/ReferencePipeline.java b/android-35/java/util/stream/ReferencePipeline.java
new file mode 100644
index 0000000..07bd046
--- /dev/null
+++ b/android-35/java/util/stream/ReferencePipeline.java
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import jdk.internal.access.SharedSecrets;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code U}.
+ *
+ * @param <P_IN> type of elements in the upstream source
+ * @param <P_OUT> type of elements in produced by this stage
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class ReferencePipeline<P_IN, P_OUT>
+        extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
+        implements Stream<P_OUT>  {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Supplier<? extends Spliterator<?>> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Spliterator<?> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     */
+    ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<P_OUT> evaluateToNode(PipelineHelper<P_OUT> helper,
+                                        Spliterator<P_IN> spliterator,
+                                        boolean flattenTree,
+                                        IntFunction<P_OUT[]> generator) {
+        return Nodes.collect(helper, spliterator, flattenTree, generator);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<P_OUT> wrap(PipelineHelper<P_OUT> ph,
+                                     Supplier<Spliterator<P_IN>> supplier,
+                                     boolean isParallel) {
+        return new StreamSpliterators.WrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator<P_OUT> lazySpliterator(Supplier<? extends Spliterator<P_OUT>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator<>(supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final boolean forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
+        boolean cancelled;
+        do { } while (!(cancelled = sink.cancellationRequested()) && spliterator.tryAdvance(sink));
+        return cancelled;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown, IntFunction<P_OUT[]> generator) {
+        return Nodes.builder(exactSizeIfKnown, generator);
+    }
+
+
+    // BaseStream
+
+    @Override
+    public final Iterator<P_OUT> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+
+    // Stream
+
+    // Stateless intermediate operations from Stream
+
+    @Override
+    public Stream<P_OUT> unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        if (predicate.test(u))
+                            downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.apply(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(ToIntFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsInt(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(ToLongFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsLong(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(ToDoubleFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsDouble(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <R> Stream<R> flatMap(Function<? super P_OUT, ? extends Stream<? extends R>> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (Stream<? extends R> result = mapper.apply(u)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstream);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstream));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        // If this method is called then an operation within the stream
+                        // pipeline is short-circuiting (see AbstractPipeline.copyInto).
+                        // Note that we cannot differentiate between an upstream or
+                        // downstream operation
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMapToInt(Function<? super P_OUT, ? extends IntStream> mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    IntConsumer downstreamAsInt = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (IntStream result = mapper.apply(u)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsInt);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsInt));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMapToDouble(Function<? super P_OUT, ? extends DoubleStream> mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    DoubleConsumer downstreamAsDouble = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (DoubleStream result = mapper.apply(u)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsDouble);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsDouble));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMapToLong(Function<? super P_OUT, ? extends LongStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    // true if cancellationRequested() has been called
+                    boolean cancellationRequestedCalled;
+
+                    // cache the consumer to avoid creation on every accepted element
+                    LongConsumer downstreamAsLong = downstream::accept;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (LongStream result = mapper.apply(u)) {
+                            if (result != null) {
+                                if (!cancellationRequestedCalled) {
+                                    result.sequential().forEach(downstreamAsLong);
+                                }
+                                else {
+                                    var s = result.sequential().spliterator();
+                                    do { } while (!downstream.cancellationRequested() && s.tryAdvance(downstreamAsLong));
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        cancellationRequestedCalled = true;
+                        return downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <R> Stream<R> mapMulti(BiConsumer<? super P_OUT, ? super Consumer<R>> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<>(this, StreamShape.REFERENCE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(P_OUT u) {
+                        mapper.accept(u, (Consumer<R>) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapMultiToInt(BiConsumer<? super P_OUT, ? super IntConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<>(this, StreamShape.REFERENCE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(P_OUT u) {
+                        mapper.accept(u, (IntConsumer)downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapMultiToLong(BiConsumer<? super P_OUT, ? super LongConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<>(this, StreamShape.REFERENCE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(P_OUT u) {
+                        mapper.accept(u, (LongConsumer) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+
+    @Override
+    public final DoubleStream mapMultiToDouble(BiConsumer<? super P_OUT, ? super DoubleConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<>(this, StreamShape.REFERENCE,
+                StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<>(sink) {
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public void accept(P_OUT u) {
+                        mapper.accept(u, (DoubleConsumer) downstream);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        action.accept(u);
+                        downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate operations from Stream
+
+    @Override
+    public final Stream<P_OUT> distinct() {
+        return DistinctOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted() {
+        return SortedOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted(Comparator<? super P_OUT> comparator) {
+        return SortedOps.makeRef(this, comparator);
+    }
+
+    @Override
+    public final Stream<P_OUT> limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeRef(this, 0, maxSize);
+    }
+
+    @Override
+    public final Stream<P_OUT> skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeRef(this, n, -1);
+    }
+
+    @Override
+    public final Stream<P_OUT> takeWhile(Predicate<? super P_OUT> predicate) {
+        return WhileOps.makeTakeWhileRef(this, predicate);
+    }
+
+    @Override
+    public final Stream<P_OUT> dropWhile(Predicate<? super P_OUT> predicate) {
+        return WhileOps.makeDropWhileRef(this, predicate);
+    }
+
+    // Terminal operations from Stream
+
+    @Override
+    public void forEach(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, true));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <A> A[] toArray(IntFunction<A[]> generator) {
+        // Since A has no relation to U (not possible to declare that A is an upper bound of U)
+        // there will be no static type checking.
+        // Therefore use a raw type and assume A == U rather than propagating the separation of A and U
+        // throughout the code-base.
+        // The runtime type of U is never checked for equality with the component type of the runtime type of A[].
+        // Runtime checking will be performed when an element is stored in A[], thus if A is not a
+        // super type of U an ArrayStoreException will be thrown.
+        @SuppressWarnings("rawtypes")
+        IntFunction rawGenerator = (IntFunction) generator;
+        // Android-changed: Eclipse compiler requires explicit (Node<A[]>) cast (b/29399275).
+        return (A[]) Nodes.flatten((Node<A[]>) evaluateToArrayNode(rawGenerator), rawGenerator)
+                .asArray(rawGenerator);
+    }
+
+    @Override
+    public final Object[] toArray() {
+        return toArray(Object[]::new);
+    }
+
+    @Override
+    public List<P_OUT> toList() {
+        return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(this.toArray());
+    }
+
+    @Override
+    public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final Optional<P_OUT> findFirst() {
+        return evaluate(FindOps.makeRef(true));
+    }
+
+    @Override
+    public final Optional<P_OUT> findAny() {
+        return evaluate(FindOps.makeRef(false));
+    }
+
+    @Override
+    public final P_OUT reduce(final P_OUT identity, final BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, accumulator));
+    }
+
+    @Override
+    public final Optional<P_OUT> reduce(BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(accumulator));
+    }
+
+    @Override
+    public final <R> R reduce(R identity, BiFunction<R, ? super P_OUT, R> accumulator, BinaryOperator<R> combiner) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, combiner));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
+        A container;
+        if (isParallel()
+                && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
+                && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
+            container = collector.supplier().get();
+            BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
+            forEach(u -> accumulator.accept(container, u));
+        }
+        else {
+            container = evaluate(ReduceOps.makeRef(collector));
+        }
+        return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
+               ? (R) container
+               : collector.finisher().apply(container);
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               BiConsumer<R, ? super P_OUT> accumulator,
+                               BiConsumer<R, R> combiner) {
+        return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
+    }
+
+    @Override
+    public final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.maxBy(comparator));
+    }
+
+    @Override
+    public final Optional<P_OUT> min(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.minBy(comparator));
+
+    }
+
+    @Override
+    public final long count() {
+        return evaluate(ReduceOps.makeRefCounting());
+    }
+
+    //
+
+    /**
+     * Source stage of a ReferencePipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<?>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<?> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateful intermediate operation
+         * to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<E_OUT[]> generator);
+    }
+}
diff --git a/android-35/java/util/stream/Sink.java b/android-35/java/util/stream/Sink.java
new file mode 100644
index 0000000..491701b
--- /dev/null
+++ b/android-35/java/util/stream/Sink.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An extension of {@link Consumer} used to conduct values through the stages of
+ * a stream pipeline, with additional methods to manage size information,
+ * control flow, etc.  Before calling the {@code accept()} method on a
+ * {@code Sink} for the first time, you must first call the {@code begin()}
+ * method to inform it that data is coming (optionally informing the sink how
+ * much data is coming), and after all data has been sent, you must call the
+ * {@code end()} method.  After calling {@code end()}, you should not call
+ * {@code accept()} without again calling {@code begin()}.  {@code Sink} also
+ * offers a mechanism by which the sink can cooperatively signal that it does
+ * not wish to receive any more data (the {@code cancellationRequested()}
+ * method), which a source can poll before sending more data to the
+ * {@code Sink}.
+ *
+ * <p>A sink may be in one of two states: an initial state and an active state.
+ * It starts out in the initial state; the {@code begin()} method transitions
+ * it to the active state, and the {@code end()} method transitions it back into
+ * the initial state, where it can be re-used.  Data-accepting methods (such as
+ * {@code accept()} are only valid in the active state.
+ *
+ * @apiNote
+ * A stream pipeline consists of a source, zero or more intermediate stages
+ * (such as filtering or mapping), and a terminal stage, such as reduction or
+ * for-each.  For concreteness, consider the pipeline:
+ *
+ * <pre>{@code
+ *     int longestStringLengthStartingWithA
+ *         = strings.stream()
+ *                  .filter(s -> s.startsWith("A"))
+ *                  .mapToInt(String::length)
+ *                  .max();
+ * }</pre>
+ *
+ * <p>Here, we have three stages, filtering, mapping, and reducing.  The
+ * filtering stage consumes strings and emits a subset of those strings; the
+ * mapping stage consumes strings and emits ints; the reduction stage consumes
+ * those ints and computes the maximal value.
+ *
+ * <p>A {@code Sink} instance is used to represent each stage of this pipeline,
+ * whether the stage accepts objects, ints, longs, or doubles.  Sink has entry
+ * points for {@code accept(Object)}, {@code accept(int)}, etc, so that we do
+ * not need a specialized interface for each primitive specialization.  (It
+ * might be called a "kitchen sink" for this omnivorous tendency.)  The entry
+ * point to the pipeline is the {@code Sink} for the filtering stage, which
+ * sends some elements "downstream" -- into the {@code Sink} for the mapping
+ * stage, which in turn sends integral values downstream into the {@code Sink}
+ * for the reduction stage. The {@code Sink} implementations associated with a
+ * given stage is expected to know the data type for the next stage, and call
+ * the correct {@code accept} method on its downstream {@code Sink}.  Similarly,
+ * each stage must implement the correct {@code accept} method corresponding to
+ * the data type it accepts.
+ *
+ * <p>The specialized subtypes such as {@link Sink.OfInt} override
+ * {@code accept(Object)} to call the appropriate primitive specialization of
+ * {@code accept}, implement the appropriate primitive specialization of
+ * {@code Consumer}, and re-abstract the appropriate primitive specialization of
+ * {@code accept}.
+ *
+ * <p>The chaining subtypes such as {@link ChainedInt} not only implement
+ * {@code Sink.OfInt}, but also maintain a {@code downstream} field which
+ * represents the downstream {@code Sink}, and implement the methods
+ * {@code begin()}, {@code end()}, and {@code cancellationRequested()} to
+ * delegate to the downstream {@code Sink}.  Most implementations of
+ * intermediate operations will use these chaining wrappers.  For example, the
+ * mapping stage in the above example would look like:
+ *
+ * <pre>{@code
+ *     IntSink is = new Sink.ChainedReference<U>(sink) {
+ *         public void accept(U u) {
+ *             downstream.accept(mapper.applyAsInt(u));
+ *         }
+ *     };
+ * }</pre>
+ *
+ * <p>Here, we implement {@code Sink.ChainedReference<U>}, meaning that we expect
+ * to receive elements of type {@code U} as input, and pass the downstream sink
+ * to the constructor.  Because the next stage expects to receive integers, we
+ * must call the {@code accept(int)} method when emitting values to the downstream.
+ * The {@code accept()} method applies the mapping function from {@code U} to
+ * {@code int} and passes the resulting value to the downstream {@code Sink}.
+ *
+ * @param <T> type of elements for value streams
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Sink<T> extends Consumer<T> {
+    /**
+     * Resets the sink state to receive a fresh data set.  This must be called
+     * before sending any data to the sink.  After calling {@link #end()},
+     * you may call this method to reset the sink for another calculation.
+     * @param size The exact size of the data to be pushed downstream, if
+     * known or {@code -1} if unknown or infinite.
+     *
+     * <p>Prior to this call, the sink must be in the initial state, and after
+     * this call it is in the active state.
+     */
+    default void begin(long size) {}
+
+    /**
+     * Indicates that all elements have been pushed.  If the {@code Sink} is
+     * stateful, it should send any stored state downstream at this time, and
+     * should clear any accumulated state (and associated resources).
+     *
+     * <p>Prior to this call, the sink must be in the active state, and after
+     * this call it is returned to the initial state.
+     */
+    default void end() {}
+
+    /**
+     * Indicates that this {@code Sink} does not wish to receive any more data.
+     *
+     * @implSpec The default implementation always returns false.
+     *
+     * @return true if cancellation is requested
+     */
+    default boolean cancellationRequested() {
+        return false;
+    }
+
+    /**
+     * Accepts an int value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept int values
+     */
+    default void accept(int value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a long value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept long values
+     */
+    default void accept(long value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a double value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept double values
+     */
+    default void accept(double value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Integer>}, re-abstracts
+     * {@code accept(int)}, and wires {@code accept(Integer)} to bridge to
+     * {@code accept(int)}.
+     */
+    interface OfInt extends Sink<Integer>, IntConsumer {
+        @Override
+        void accept(int value);
+
+        @Override
+        default void accept(Integer i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+            accept(i.intValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Long>}, re-abstracts
+     * {@code accept(long)}, and wires {@code accept(Long)} to bridge to
+     * {@code accept(long)}.
+     */
+    interface OfLong extends Sink<Long>, LongConsumer {
+        @Override
+        void accept(long value);
+
+        @Override
+        default void accept(Long i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfLong.accept(Long)");
+            accept(i.longValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Double>}, re-abstracts
+     * {@code accept(double)}, and wires {@code accept(Double)} to bridge to
+     * {@code accept(double)}.
+     */
+    interface OfDouble extends Sink<Double>, DoubleConsumer {
+        @Override
+        void accept(double value);
+
+        @Override
+        default void accept(Double i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfDouble.accept(Double)");
+            accept(i.doubleValue());
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink<T>}.  The
+     * implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    abstract static class ChainedReference<T, E_OUT> implements Sink<T> {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedReference(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfInt}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    abstract static class ChainedInt<E_OUT> implements Sink.OfInt {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedInt(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfLong}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    abstract static class ChainedLong<E_OUT> implements Sink.OfLong {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedLong(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfDouble}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    abstract static class ChainedDouble<E_OUT> implements Sink.OfDouble {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedDouble(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+}
diff --git a/android-35/java/util/stream/SliceOps.java b/android-35/java/util/stream/SliceOps.java
new file mode 100644
index 0000000..2a1e31e
--- /dev/null
+++ b/android-35/java/util/stream/SliceOps.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.IntFunction;
+
+/**
+ * Factory for instances of a short-circuiting stateful intermediate operations
+ * that produce subsequences of their input stream.
+ *
+ * @since 1.8
+ */
+final class SliceOps {
+
+    // No instances
+    private SliceOps() { }
+
+    /**
+     * Calculates the sliced size given the current size, number of elements
+     * skip, and the number of elements to limit.
+     *
+     * @param size the current size
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the sliced size
+     */
+    private static long calcSize(long size, long skip, long limit) {
+        return size >= 0 ? Math.max(0, Math.min(size - skip, limit)) : -1;
+    }
+
+    /**
+     * Calculates the slice fence, which is one past the index of the slice
+     * range
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the slice fence.
+     */
+    private static long calcSliceFence(long skip, long limit) {
+        long sliceFence = limit >= 0 ? skip + limit : Long.MAX_VALUE;
+        // Check for overflow
+        return (sliceFence >= 0) ? sliceFence : Long.MAX_VALUE;
+    }
+
+    /**
+     * Creates a slice spliterator given a stream shape governing the
+     * spliterator type.  Requires that the underlying Spliterator
+     * be SUBSIZED.
+     */
+    private static <P_IN> Spliterator<P_IN> sliceSpliterator(StreamShape shape,
+                                                             Spliterator<P_IN> s,
+                                                             long skip, long limit) {
+        assert s.hasCharacteristics(Spliterator.SUBSIZED);
+        long sliceFence = calcSliceFence(skip, limit);
+        @SuppressWarnings("unchecked")
+        Spliterator<P_IN> sliceSpliterator = (Spliterator<P_IN>) switch (shape) {
+            case REFERENCE
+                -> new StreamSpliterators.SliceSpliterator.OfRef<>(s, skip, sliceFence);
+            case INT_VALUE
+                -> new StreamSpliterators.SliceSpliterator.OfInt((Spliterator.OfInt) s, skip, sliceFence);
+            case LONG_VALUE
+                -> new StreamSpliterators.SliceSpliterator.OfLong((Spliterator.OfLong) s, skip, sliceFence);
+            case DOUBLE_VALUE
+                -> new StreamSpliterators.SliceSpliterator.OfDouble((Spliterator.OfDouble) s, skip, sliceFence);
+        };
+        return sliceSpliterator;
+    }
+
+    /**
+     * Appends a "slice" operation to the provided stream.  The slice operation
+     * may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param skip the number of elements to skip.  Must be >= 0.
+     * @param limit the maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                        long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        long normalizedLimit = limit >= 0 ? limit : Long.MAX_VALUE;
+
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      flags(limit)) {
+            @Override
+            long exactOutputSize(long previousSize) {
+                return calcSize(previousSize, skip, normalizedLimit);
+            }
+
+            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
+                                                         long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfRef<>(
+                            helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    // @@@ OOMEs will occur for LongStream.range(0, Long.MAX_VALUE).filter(i -> true).limit(n)
+                    //     when n * parallelismLevel is sufficiently large.
+                    //     Need to adjust the target size of splitting for the
+                    //     SliceTask from say (size / k) to say min(size / k, 1 << 14)
+                    //     This will limit the size of the buffers created at the leaf nodes
+                    //     cancellation will be more aggressive cancelling later tasks
+                    //     if the target slice size has been reached from a given task,
+                    //     cancellation should also clear local results if any
+                    return new SliceTask<>(this, helper, spliterator, Nodes.castingArray(), skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collect(helper, s, true, generator);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator<T> s =  unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collect(this, s, true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                return new Sink.ChainedReference<>(sink) {
+                    long n = skip;
+                    long m = normalizedLimit;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(T t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided IntStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream An IntStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream,
+                                    long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        long normalizedLimit = limit >= 0 ? limit : Long.MAX_VALUE;
+
+        return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE,
+                                                   flags(limit)) {
+            @Override
+            long exactOutputSize(long previousSize) {
+                return calcSize(previousSize, skip, normalizedLimit);
+            }
+
+            Spliterator.OfInt unorderedSkipLimitSpliterator(
+                    Spliterator.OfInt s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfInt(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Integer[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Integer[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectInt(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfInt s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectInt(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<>(sink) {
+                    long n = skip;
+                    long m = normalizedLimit;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided LongStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A LongStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static LongStream makeLong(AbstractPipeline<?, Long, ?> upstream,
+                                      long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        long normalizedLimit = limit >= 0 ? limit : Long.MAX_VALUE;
+
+        return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE,
+                                                 flags(limit)) {
+            @Override
+            long exactOutputSize(long previousSize) {
+                return calcSize(previousSize, skip, normalizedLimit);
+            }
+
+            Spliterator.OfLong unorderedSkipLimitSpliterator(
+                    Spliterator.OfLong s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfLong(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Long[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<Long[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectLong(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfLong s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectLong(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<>(sink) {
+                    long n = skip;
+                    long m = normalizedLimit;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided DoubleStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A DoubleStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream,
+                                          long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        long normalizedLimit = limit >= 0 ? limit : Long.MAX_VALUE;
+
+        return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE,
+                                                     flags(limit)) {
+            @Override
+            long exactOutputSize(long previousSize) {
+                return calcSize(previousSize, skip, normalizedLimit);
+            }
+
+            Spliterator.OfDouble unorderedSkipLimitSpliterator(
+                    Spliterator.OfDouble s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Double[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                   Spliterator<P_IN> spliterator,
+                                                   IntFunction<Double[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectDouble(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfDouble s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectDouble(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<>(sink) {
+                    long n = skip;
+                    long m = normalizedLimit;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    private static int flags(long limit) {
+        return StreamOpFlag.IS_SIZE_ADJUSTING | ((limit != -1) ? StreamOpFlag.IS_SHORT_CIRCUIT : 0);
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing slice computation.
+     *
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class SliceTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, SliceTask<P_IN, P_OUT>> {
+        private final AbstractPipeline<P_OUT, P_OUT, ?> op;
+        private final IntFunction<P_OUT[]> generator;
+        private final long targetOffset, targetSize;
+        private long thisNodeSize;
+
+        private volatile boolean completed;
+
+        SliceTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
+                  PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator,
+                  IntFunction<P_OUT[]> generator,
+                  long offset, long size) {
+            super(helper, spliterator);
+            this.op = op;
+            this.generator = generator;
+            this.targetOffset = offset;
+            this.targetSize = size;
+        }
+
+        SliceTask(SliceTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+            this.generator = parent.generator;
+            this.targetOffset = parent.targetOffset;
+            this.targetSize = parent.targetSize;
+        }
+
+        @Override
+        protected SliceTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new SliceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<P_OUT> getEmptyResult() {
+            return Nodes.emptyNode(op.getOutputShape());
+        }
+
+        @Override
+        protected final Node<P_OUT> doLeaf() {
+            if (isRoot()) {
+                long sizeIfKnown = StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
+                                   ? op.exactOutputSizeIfKnown(spliterator)
+                                   : -1;
+                final Node.Builder<P_OUT> nb = op.makeNodeBuilder(sizeIfKnown, generator);
+                Sink<P_OUT> opSink = op.opWrapSink(helper.getStreamAndOpFlags(), nb);
+                helper.copyIntoWithCancel(helper.wrapSink(opSink), spliterator);
+                // There is no need to truncate since the op performs the
+                // skipping and limiting of elements
+                return nb.build();
+            }
+            else {
+                final Node.Builder<P_OUT> nb = op.makeNodeBuilder(-1, generator);
+                if (targetOffset == 0) { // limit only
+                    Sink<P_OUT> opSink = op.opWrapSink(helper.getStreamAndOpFlags(), nb);
+                    helper.copyIntoWithCancel(helper.wrapSink(opSink), spliterator);
+                }
+                else {
+                    helper.wrapAndCopyInto(nb, spliterator);
+                }
+                Node<P_OUT> node = nb.build();
+                thisNodeSize = node.count();
+                completed = true;
+                spliterator = null;
+                return node;
+            }
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                Node<P_OUT> result;
+                thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
+                if (canceled) {
+                    thisNodeSize = 0;
+                    result = getEmptyResult();
+                }
+                else if (thisNodeSize == 0)
+                    result = getEmptyResult();
+                else if (leftChild.thisNodeSize == 0)
+                    result = rightChild.getLocalResult();
+                else {
+                    result = Nodes.conc(op.getOutputShape(),
+                                        leftChild.getLocalResult(), rightChild.getLocalResult());
+                }
+                setLocalResult(isRoot() ? doTruncate(result) : result);
+                completed = true;
+            }
+            if (targetSize >= 0
+                && !isRoot()
+                && isLeftCompleted(targetOffset + targetSize))
+                    cancelLaterNodes();
+
+            super.onCompletion(caller);
+        }
+
+        @Override
+        protected void cancel() {
+            super.cancel();
+            if (completed)
+                setLocalResult(getEmptyResult());
+        }
+
+        private Node<P_OUT> doTruncate(Node<P_OUT> input) {
+            long to = targetSize >= 0 ? Math.min(input.count(), targetOffset + targetSize) : thisNodeSize;
+            return input.truncate(targetOffset, to, generator);
+        }
+
+        /**
+         * Determine if the number of completed elements in this node and nodes
+         * to the left of this node is greater than or equal to the target size.
+         *
+         * @param target the target size
+         * @return true if the number of elements is greater than or equal to
+         *         the target size, otherwise false.
+         */
+        private boolean isLeftCompleted(long target) {
+            long size = completed ? thisNodeSize : completedSize(target);
+            if (size >= target)
+                return true;
+            for (SliceTask<P_IN, P_OUT> parent = getParent(), node = this;
+                 parent != null;
+                 node = parent, parent = parent.getParent()) {
+                if (node == parent.rightChild) {
+                    SliceTask<P_IN, P_OUT> left = parent.leftChild;
+                    if (left != null) {
+                        size += left.completedSize(target);
+                        if (size >= target)
+                            return true;
+                    }
+                }
+            }
+            return size >= target;
+        }
+
+        /**
+         * Compute the number of completed elements in this node.
+         * <p>
+         * Computation terminates if all nodes have been processed or the
+         * number of completed elements is greater than or equal to the target
+         * size.
+         *
+         * @param target the target size
+         * @return the number of completed elements
+         */
+        private long completedSize(long target) {
+            if (completed)
+                return thisNodeSize;
+            else {
+                SliceTask<P_IN, P_OUT> left = leftChild;
+                SliceTask<P_IN, P_OUT> right = rightChild;
+                if (left == null || right == null) {
+                    // must be completed
+                    return thisNodeSize;
+                }
+                else {
+                    long leftSize = left.completedSize(target);
+                    return (leftSize >= target) ? leftSize : leftSize + right.completedSize(target);
+                }
+            }
+        }
+    }
+}
diff --git a/android-35/java/util/stream/SortedOps.java b/android-35/java/util/stream/SortedOps.java
new file mode 100644
index 0000000..91892eb
--- /dev/null
+++ b/android-35/java/util/stream/SortedOps.java
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+
+/**
+ * Factory methods for transforming streams into sorted streams.
+ *
+ * @since 1.8
+ */
+final class SortedOps {
+
+    private SortedOps() { }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new OfRef<>(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param comparator the comparator to order elements by
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                Comparator<? super T> comparator) {
+        return new OfRef<>(upstream, comparator);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream) {
+        return new OfInt(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> LongStream makeLong(AbstractPipeline<?, Long, ?> upstream) {
+        return new OfLong(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream) {
+        return new OfDouble(upstream);
+    }
+
+    /**
+     * Specialized subtype for sorting reference streams
+     */
+    private static final class OfRef<T> extends ReferencePipeline.StatefulOp<T, T> {
+        /**
+         * Comparator used for sorting
+         */
+        private final boolean isNaturalSort;
+        private final Comparator<? super T> comparator;
+
+        /**
+         * Sort using natural order of {@literal <T>} which must be
+         * {@code Comparable}.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+            this.isNaturalSort = true;
+            // Will throw CCE when we try to sort if T is not Comparable
+            @SuppressWarnings("unchecked")
+            Comparator<? super T> comp = (Comparator<? super T>) Comparator.naturalOrder();
+            this.comparator = comp;
+        }
+
+        /**
+         * Sort using the provided comparator.
+         *
+         * @param comparator The comparator to be used to evaluate ordering.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream, Comparator<? super T> comparator) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED);
+            this.isNaturalSort = false;
+            this.comparator = Objects.requireNonNull(comparator);
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+            Objects.requireNonNull(sink);
+
+            // If the input is already naturally sorted and this operation
+            // also naturally sorted then this is a no-op
+            if (StreamOpFlag.SORTED.isKnown(flags) && isNaturalSort)
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedRefSortingSink<>(sink, comparator);
+            else
+                return new RefSortingSink<>(sink, comparator);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            // If the input is already naturally sorted and this operation
+            // naturally sorts then collect the output
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags()) && isNaturalSort) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
+                T[] flattenedData = helper.evaluate(spliterator, true, generator).asArray(generator);
+                Arrays.parallelSort(flattenedData, comparator);
+                return Nodes.node(flattenedData);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting int streams.
+     */
+    private static final class OfInt extends IntPipeline.StatefulOp<Integer> {
+        OfInt(AbstractPipeline<?, Integer, ?> upstream) {
+            super(upstream, StreamShape.INT_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedIntSortingSink(sink);
+            else
+                return new IntSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<Integer[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfInt n = (Node.OfInt) helper.evaluate(spliterator, true, generator);
+
+                int[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting long streams.
+     */
+    private static final class OfLong extends LongPipeline.StatefulOp<Long> {
+        OfLong(AbstractPipeline<?, Long, ?> upstream) {
+            super(upstream, StreamShape.LONG_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedLongSortingSink(sink);
+            else
+                return new LongSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Long[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfLong n = (Node.OfLong) helper.evaluate(spliterator, true, generator);
+
+                long[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting double streams.
+     */
+    private static final class OfDouble extends DoublePipeline.StatefulOp<Double> {
+        OfDouble(AbstractPipeline<?, Double, ?> upstream) {
+            super(upstream, StreamShape.DOUBLE_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedDoubleSortingSink(sink);
+            else
+                return new DoubleSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Double[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfDouble n = (Node.OfDouble) helper.evaluate(spliterator, true, generator);
+
+                double[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on reference streams.
+     *
+     * <p>
+     * Note: documentation below applies to reference and all primitive sinks.
+     * <p>
+     * Sorting sinks first accept all elements, buffering then into an array
+     * or a re-sizable data structure, if the size of the pipeline is known or
+     * unknown respectively.  At the end of the sink protocol those elements are
+     * sorted and then pushed downstream.
+     * This class records if {@link #cancellationRequested} is called.  If so it
+     * can be inferred that the source pushing source elements into the pipeline
+     * knows that the pipeline is short-circuiting.  In such cases sub-classes
+     * pushing elements downstream will preserve the short-circuiting protocol
+     * by calling {@code downstream.cancellationRequested()} and checking the
+     * result is {@code false} before an element is pushed.
+     * <p>
+     * Note that the above behaviour is an optimization for sorting with
+     * sequential streams.  It is not an error that more elements, than strictly
+     * required to produce a result, may flow through the pipeline.  This can
+     * occur, in general (not restricted to just sorting), for short-circuiting
+     * parallel pipelines.
+     */
+    private abstract static class AbstractRefSortingSink<T> extends Sink.ChainedReference<T, T> {
+        protected final Comparator<? super T> comparator;
+        // @@@ could be a lazy final value, if/when support is added
+        // true if cancellationRequested() has been called
+        protected boolean cancellationRequestedCalled;
+
+        AbstractRefSortingSink(Sink<? super T> downstream, Comparator<? super T> comparator) {
+            super(downstream);
+            this.comparator = comparator;
+        }
+
+        /**
+         * Records is cancellation is requested so short-circuiting behaviour
+         * can be preserved when the sorted elements are pushed downstream.
+         *
+         * @return false, as this sink never short-circuits.
+         */
+        @Override
+        public final boolean cancellationRequested() {
+            // If this method is called then an operation within the stream
+            // pipeline is short-circuiting (see AbstractPipeline.copyInto).
+            // Note that we cannot differentiate between an upstream or
+            // downstream operation
+            cancellationRequestedCalled = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED reference streams.
+     */
+    private static final class SizedRefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private T[] array;
+        private int offset;
+
+        SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = (T[]) new Object[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset, comparator);
+            downstream.begin(offset);
+            if (!cancellationRequestedCalled) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on reference streams.
+     */
+    private static final class RefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private ArrayList<T> list;
+
+        RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            list = (size >= 0) ? new ArrayList<>((int) size) : new ArrayList<>();
+        }
+
+        @Override
+        public void end() {
+            list.sort(comparator);
+            downstream.begin(list.size());
+            if (!cancellationRequestedCalled) {
+                list.forEach(downstream::accept);
+            }
+            else {
+                for (T t : list) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(t);
+                }
+            }
+            downstream.end();
+            list = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            list.add(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on int streams.
+     */
+    private abstract static class AbstractIntSortingSink extends Sink.ChainedInt<Integer> {
+        // true if cancellationRequested() has been called
+        protected boolean cancellationRequestedCalled;
+
+        AbstractIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationRequestedCalled = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED int streams.
+     */
+    private static final class SizedIntSortingSink extends AbstractIntSortingSink {
+        private int[] array;
+        private int offset;
+
+        SizedIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new int[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationRequestedCalled) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(int t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on int streams.
+     */
+    private static final class IntSortingSink extends AbstractIntSortingSink {
+        private SpinedBuffer.OfInt b;
+
+        IntSortingSink(Sink<? super Integer> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
+        }
+
+        @Override
+        public void end() {
+            int[] ints = b.asPrimitiveArray();
+            Arrays.sort(ints);
+            downstream.begin(ints.length);
+            if (!cancellationRequestedCalled) {
+                for (int anInt : ints)
+                    downstream.accept(anInt);
+            }
+            else {
+                for (int anInt : ints) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(anInt);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(int t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private abstract static class AbstractLongSortingSink extends Sink.ChainedLong<Long> {
+        // true if cancellationRequested() has been called
+        protected boolean cancellationRequestedCalled;
+
+        AbstractLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationRequestedCalled = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED long streams.
+     */
+    private static final class SizedLongSortingSink extends AbstractLongSortingSink {
+        private long[] array;
+        private int offset;
+
+        SizedLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new long[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationRequestedCalled) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(long t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on long streams.
+     */
+    private static final class LongSortingSink extends AbstractLongSortingSink {
+        private SpinedBuffer.OfLong b;
+
+        LongSortingSink(Sink<? super Long> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong();
+        }
+
+        @Override
+        public void end() {
+            long[] longs = b.asPrimitiveArray();
+            Arrays.sort(longs);
+            downstream.begin(longs.length);
+            if (!cancellationRequestedCalled) {
+                for (long aLong : longs)
+                    downstream.accept(aLong);
+            }
+            else {
+                for (long aLong : longs) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aLong);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(long t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private abstract static class AbstractDoubleSortingSink extends Sink.ChainedDouble<Double> {
+        // true if cancellationRequested() has been called
+        protected boolean cancellationRequestedCalled;
+
+        AbstractDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationRequestedCalled = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED double streams.
+     */
+    private static final class SizedDoubleSortingSink extends AbstractDoubleSortingSink {
+        private double[] array;
+        private int offset;
+
+        SizedDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new double[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationRequestedCalled) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(double t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on double streams.
+     */
+    private static final class DoubleSortingSink extends AbstractDoubleSortingSink {
+        private SpinedBuffer.OfDouble b;
+
+        DoubleSortingSink(Sink<? super Double> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble();
+        }
+
+        @Override
+        public void end() {
+            double[] doubles = b.asPrimitiveArray();
+            Arrays.sort(doubles);
+            downstream.begin(doubles.length);
+            if (!cancellationRequestedCalled) {
+                for (double aDouble : doubles)
+                    downstream.accept(aDouble);
+            }
+            else {
+                for (double aDouble : doubles) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aDouble);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(double t) {
+            b.accept(t);
+        }
+    }
+}
diff --git a/android-35/java/util/stream/SpinedBuffer.java b/android-35/java/util/stream/SpinedBuffer.java
new file mode 100644
index 0000000..d21518a
--- /dev/null
+++ b/android-35/java/util/stream/SpinedBuffer.java
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An ordered collection of elements.  Elements can be added, but not removed.
+ * Goes through a building phase, during which elements can be added, and a
+ * traversal phase, during which elements can be traversed in order but no
+ * further modifications are possible.
+ *
+ * <p> One or more arrays are used to store elements. The use of a multiple
+ * arrays has better performance characteristics than a single array used by
+ * {@link ArrayList}, as when the capacity of the list needs to be increased
+ * no copying of elements is required.  This is usually beneficial in the case
+ * where the results will be traversed a small number of times.
+ *
+ * @param <E> the type of elements in this list
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public class SpinedBuffer<E>
+        extends AbstractSpinedBuffer
+        implements Consumer<E>, Iterable<E> {
+
+    /*
+     * We optimistically hope that all the data will fit into the first chunk,
+     * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+     * prematurely.  So methods must be prepared to deal with these arrays being
+     * null.  If spine is non-null, then spineIndex points to the current chunk
+     * within the spine, otherwise it is zero.  The spine and priorElementCount
+     * arrays are always the same size, and for any i <= spineIndex,
+     * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+     *
+     * The curChunk pointer is always valid.  The elementIndex is the index of
+     * the next element to be written in curChunk; this may be past the end of
+     * curChunk so we have to check before writing. When we inflate the spine
+     * array, curChunk becomes the first element in it.  When we clear the
+     * buffer, we discard all chunks except the first one, which we clear,
+     * restoring it to the initial single-chunk state.
+     */
+
+    /**
+     * Chunk that we're currently writing into; may or may not be aliased with
+     * the first element of the spine.
+     */
+    protected E[] curChunk;
+
+    /**
+     * All chunks, or null if there is only one chunk.
+     */
+    protected E[][] spine;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer(int initialCapacity) {
+        super(initialCapacity);
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of sixteen.
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer() {
+        super();
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Returns the current capacity of the buffer
+     */
+    protected long capacity() {
+        return (spineIndex == 0)
+               ? curChunk.length
+               : priorElementCount[spineIndex] + spine[spineIndex].length;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void inflateSpine() {
+        if (spine == null) {
+            spine = (E[][]) new Object[MIN_SPINE_SIZE][];
+            priorElementCount = new long[MIN_SPINE_SIZE];
+            spine[0] = curChunk;
+        }
+    }
+
+    /**
+     * Ensure that the buffer has at least capacity to hold the target size
+     */
+    @SuppressWarnings("unchecked")
+    protected final void ensureCapacity(long targetSize) {
+        long capacity = capacity();
+        if (targetSize > capacity) {
+            inflateSpine();
+            for (int i=spineIndex+1; targetSize > capacity; i++) {
+                if (i >= spine.length) {
+                    int newSpineSize = spine.length * 2;
+                    spine = Arrays.copyOf(spine, newSpineSize);
+                    priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                }
+                int nextChunkSize = chunkSize(i);
+                spine[i] = (E[]) new Object[nextChunkSize];
+                priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length;
+                capacity += nextChunkSize;
+            }
+        }
+    }
+
+    /**
+     * Force the buffer to increase its capacity.
+     */
+    protected void increaseCapacity() {
+        ensureCapacity(capacity() + 1);
+    }
+
+    /**
+     * Retrieve the element at the specified index.
+     */
+    public E get(long index) {
+        // @@@ can further optimize by caching last seen spineIndex,
+        // which is going to be right most of the time
+
+        // Casts to int are safe since the spine array index is the index minus
+        // the prior element count from the current spine
+        if (spineIndex == 0) {
+            if (index < elementIndex)
+                return curChunk[((int) index)];
+            else
+                throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        if (index >= count())
+            throw new IndexOutOfBoundsException(Long.toString(index));
+
+        for (int j=0; j <= spineIndex; j++)
+            if (index < priorElementCount[j] + spine[j].length)
+                return spine[j][((int) (index - priorElementCount[j]))];
+
+        throw new IndexOutOfBoundsException(Long.toString(index));
+    }
+
+    /**
+     * Copy the elements, starting at the specified offset, into the specified
+     * array.
+     */
+    public void copyInto(E[] array, int offset) {
+        long finalOffset = offset + count();
+        if (finalOffset > array.length || finalOffset < offset) {
+            throw new IndexOutOfBoundsException("does not fit");
+        }
+
+        if (spineIndex == 0)
+            System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        else {
+            // full chunks
+            for (int i=0; i < spineIndex; i++) {
+                System.arraycopy(spine[i], 0, array, offset, spine[i].length);
+                offset += spine[i].length;
+            }
+            if (elementIndex > 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        }
+    }
+
+    /**
+     * Create a new array using the specified array factory, and copy the
+     * elements into it.
+     */
+    public E[] asArray(IntFunction<E[]> arrayFactory) {
+        long size = count();
+        if (size >= Nodes.MAX_ARRAY_SIZE)
+            throw new IllegalArgumentException(Nodes.BAD_SIZE);
+        E[] result = arrayFactory.apply((int) size);
+        copyInto(result, 0);
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        if (spine != null) {
+            curChunk = spine[0];
+            for (int i=0; i<curChunk.length; i++)
+                curChunk[i] = null;
+            spine = null;
+            priorElementCount = null;
+        }
+        else {
+            for (int i=0; i<elementIndex; i++)
+                curChunk[i] = null;
+        }
+        elementIndex = 0;
+        spineIndex = 0;
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> consumer) {
+        // completed chunks, if any
+        for (int j = 0; j < spineIndex; j++)
+            for (E t : spine[j])
+                consumer.accept(t);
+
+        // current chunk
+        for (int i=0; i<elementIndex; i++)
+            consumer.accept(curChunk[i]);
+    }
+
+    @Override
+    public void accept(E e) {
+        if (elementIndex == curChunk.length) {
+            inflateSpine();
+            if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                increaseCapacity();
+            elementIndex = 0;
+            ++spineIndex;
+            curChunk = spine[spineIndex];
+        }
+        curChunk[elementIndex++] = e;
+    }
+
+    @Override
+    public String toString() {
+        List<E> list = new ArrayList<>();
+        forEach(list::add);
+        return "SpinedBuffer:" + list.toString();
+    }
+
+    private static final int SPLITERATOR_CHARACTERISTICS
+            = Spliterator.SIZED | Spliterator.ORDERED | Spliterator.SUBSIZED;
+
+    /**
+     * Return a {@link Spliterator} describing the contents of the buffer.
+     */
+    public Spliterator<E> spliterator() {
+        class Splitr implements Spliterator<E> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            E[] splChunk;
+
+            Splitr(int firstSpineIndex, int lastSpineIndex,
+                   int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    consumer.accept(splChunk[splElementIndex++]);
+
+                    if (splElementIndex == splChunk.length) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        E[] chunk = spine[sp];
+                        for (; i < chunk.length; i++) {
+                            consumer.accept(chunk[i]);
+                        }
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    E[] chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    int hElementIndex = lastSpineElementFence;
+                    for (; i < hElementIndex; i++) {
+                        consumer.accept(chunk[i]);
+                    }
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public Spliterator<E> trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    Spliterator<E> ret = new Splitr(splSpineIndex, lastSpineIndex - 1,
+                                                    splElementIndex, spine[lastSpineIndex-1].length);
+                    // position to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        Spliterator<E> ret = Arrays.spliterator(splChunk, splElementIndex, splElementIndex + t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+        return new Splitr(0, spineIndex, 0, elementIndex);
+    }
+
+    /**
+     * An ordered collection of primitive values.  Elements can be added, but
+     * not removed. Goes through a building phase, during which elements can be
+     * added, and a traversal phase, during which elements can be traversed in
+     * order but no further modifications are possible.
+     *
+     * <p> One or more arrays are used to store elements. The use of a multiple
+     * arrays has better performance characteristics than a single array used by
+     * {@link ArrayList}, as when the capacity of the list needs to be increased
+     * no copying of elements is required.  This is usually beneficial in the case
+     * where the results will be traversed a small number of times.
+     *
+     * @param <E> the wrapper type for this primitive type
+     * @param <T_ARR> the array type for this primitive type
+     * @param <T_CONS> the Consumer type for this primitive type
+     */
+    abstract static class OfPrimitive<E, T_ARR, T_CONS>
+            extends AbstractSpinedBuffer implements Iterable<E> {
+
+        /*
+         * We optimistically hope that all the data will fit into the first chunk,
+         * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+         * prematurely.  So methods must be prepared to deal with these arrays being
+         * null.  If spine is non-null, then spineIndex points to the current chunk
+         * within the spine, otherwise it is zero.  The spine and priorElementCount
+         * arrays are always the same size, and for any i <= spineIndex,
+         * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+         *
+         * The curChunk pointer is always valid.  The elementIndex is the index of
+         * the next element to be written in curChunk; this may be past the end of
+         * curChunk so we have to check before writing. When we inflate the spine
+         * array, curChunk becomes the first element in it.  When we clear the
+         * buffer, we discard all chunks except the first one, which we clear,
+         * restoring it to the initial single-chunk state.
+         */
+
+        // The chunk we're currently writing into
+        T_ARR curChunk;
+
+        // All chunks, or null if there is only one chunk
+        T_ARR[] spine;
+
+        /**
+         * Constructs an empty list with the specified initial capacity.
+         *
+         * @param  initialCapacity  the initial capacity of the list
+         * @throws IllegalArgumentException if the specified initial capacity
+         *         is negative
+         */
+        OfPrimitive(int initialCapacity) {
+            super(initialCapacity);
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        /**
+         * Constructs an empty list with an initial capacity of sixteen.
+         */
+        OfPrimitive() {
+            super();
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        @Override
+        public abstract Iterator<E> iterator();
+
+        @Override
+        public abstract void forEach(Consumer<? super E> consumer);
+
+        /** Create a new array-of-array of the proper type and size */
+        protected abstract T_ARR[] newArrayArray(int size);
+
+        /** Create a new array of the proper type and size */
+        public abstract T_ARR newArray(int size);
+
+        /** Get the length of an array */
+        protected abstract int arrayLength(T_ARR array);
+
+        /** Iterate an array with the provided consumer */
+        protected abstract void arrayForEach(T_ARR array, int from, int to,
+                                             T_CONS consumer);
+
+        protected long capacity() {
+            return (spineIndex == 0)
+                   ? arrayLength(curChunk)
+                   : priorElementCount[spineIndex] + arrayLength(spine[spineIndex]);
+        }
+
+        private void inflateSpine() {
+            if (spine == null) {
+                spine = newArrayArray(MIN_SPINE_SIZE);
+                priorElementCount = new long[MIN_SPINE_SIZE];
+                spine[0] = curChunk;
+            }
+        }
+
+        protected final void ensureCapacity(long targetSize) {
+            long capacity = capacity();
+            if (targetSize > capacity) {
+                inflateSpine();
+                for (int i=spineIndex+1; targetSize > capacity; i++) {
+                    if (i >= spine.length) {
+                        int newSpineSize = spine.length * 2;
+                        spine = Arrays.copyOf(spine, newSpineSize);
+                        priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                    }
+                    int nextChunkSize = chunkSize(i);
+                    spine[i] = newArray(nextChunkSize);
+                    priorElementCount[i] = priorElementCount[i-1] + arrayLength(spine[i - 1]);
+                    capacity += nextChunkSize;
+                }
+            }
+        }
+
+        protected void increaseCapacity() {
+            ensureCapacity(capacity() + 1);
+        }
+
+        protected int chunkFor(long index) {
+            if (spineIndex == 0) {
+                if (index < elementIndex)
+                    return 0;
+                else
+                    throw new IndexOutOfBoundsException(Long.toString(index));
+            }
+
+            if (index >= count())
+                throw new IndexOutOfBoundsException(Long.toString(index));
+
+            for (int j=0; j <= spineIndex; j++)
+                if (index < priorElementCount[j] + arrayLength(spine[j]))
+                    return j;
+
+            throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        public void copyInto(T_ARR array, int offset) {
+            long finalOffset = offset + count();
+            if (finalOffset > arrayLength(array) || finalOffset < offset) {
+                throw new IndexOutOfBoundsException("does not fit");
+            }
+
+            if (spineIndex == 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            else {
+                // full chunks
+                for (int i=0; i < spineIndex; i++) {
+                    System.arraycopy(spine[i], 0, array, offset, arrayLength(spine[i]));
+                    offset += arrayLength(spine[i]);
+                }
+                if (elementIndex > 0)
+                    System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            }
+        }
+
+        public T_ARR asPrimitiveArray() {
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T_ARR result = newArray((int) size);
+            copyInto(result, 0);
+            return result;
+        }
+
+        protected void preAccept() {
+            if (elementIndex == arrayLength(curChunk)) {
+                inflateSpine();
+                if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                    increaseCapacity();
+                elementIndex = 0;
+                ++spineIndex;
+                curChunk = spine[spineIndex];
+            }
+        }
+
+        public void clear() {
+            if (spine != null) {
+                curChunk = spine[0];
+                spine = null;
+                priorElementCount = null;
+            }
+            elementIndex = 0;
+            spineIndex = 0;
+        }
+
+        @SuppressWarnings("overloads")
+        public void forEach(T_CONS consumer) {
+            // completed chunks, if any
+            for (int j = 0; j < spineIndex; j++)
+                arrayForEach(spine[j], 0, arrayLength(spine[j]), consumer);
+
+            // current chunk
+            arrayForEach(curChunk, 0, elementIndex, consumer);
+        }
+
+        abstract class BaseSpliterator<T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>>
+                implements Spliterator.OfPrimitive<E, T_CONS, T_SPLITR> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            T_ARR splChunk;
+
+            BaseSpliterator(int firstSpineIndex, int lastSpineIndex,
+                            int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            abstract T_SPLITR newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                             int firstSpineElementIndex, int lastSpineElementFence);
+
+            abstract void arrayForOne(T_ARR array, int index, T_CONS consumer);
+
+            abstract T_SPLITR arraySpliterator(T_ARR array, int offset, int len);
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    arrayForOne(splChunk, splElementIndex++, consumer);
+
+                    if (splElementIndex == arrayLength(splChunk)) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        T_ARR chunk = spine[sp];
+                        arrayForEach(chunk, i, arrayLength(chunk), consumer);
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    T_ARR chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    arrayForEach(chunk, i, lastSpineElementFence, consumer);
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public T_SPLITR trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    T_SPLITR ret = newSpliterator(splSpineIndex, lastSpineIndex - 1,
+                                                  splElementIndex, arrayLength(spine[lastSpineIndex - 1]));
+                    // position us to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        T_SPLITR ret = arraySpliterator(splChunk, splElementIndex, t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code int} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntConsumer>
+            implements IntConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfInt() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfInt(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfInt.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected int[][] newArrayArray(int size) {
+            return new int[size][];
+        }
+
+        @Override
+        public int[] newArray(int size) {
+            return new int[size];
+        }
+
+        @Override
+        protected int arrayLength(int[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(int[] array,
+                                    int from, int to,
+                                    IntConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(int i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public int get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfInt iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfInt spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfInt>
+                    implements Spliterator.OfInt {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(int[] array, int index, IntConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfInt arraySpliterator(int[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            int[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                int[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code long} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfLong extends SpinedBuffer.OfPrimitive<Long, long[], LongConsumer>
+            implements LongConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfLong() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfLong(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfLong.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected long[][] newArrayArray(int size) {
+            return new long[size][];
+        }
+
+        @Override
+        public long[] newArray(int size) {
+            return new long[size];
+        }
+
+        @Override
+        protected int arrayLength(long[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(long[] array,
+                                    int from, int to,
+                                    LongConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(long i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public long get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfLong iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+
+        public Spliterator.OfLong spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfLong>
+                    implements Spliterator.OfLong {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(long[] array, int index, LongConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfLong arraySpliterator(long[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            long[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                long[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code double} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfDouble
+            extends SpinedBuffer.OfPrimitive<Double, double[], DoubleConsumer>
+            implements DoubleConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfDouble.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected double[][] newArrayArray(int size) {
+            return new double[size][];
+        }
+
+        @Override
+        public double[] newArray(int size) {
+            return new double[size];
+        }
+
+        @Override
+        protected int arrayLength(double[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(double[] array,
+                                    int from, int to,
+                                    DoubleConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(double i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public double get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfDouble iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfDouble spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfDouble>
+                    implements Spliterator.OfDouble {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(double[] array, int index, DoubleConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfDouble arraySpliterator(double[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            double[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                double[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+}
+
diff --git a/android-35/java/util/stream/Stream.java b/android-35/java/util/stream/Stream.java
new file mode 100644
index 0000000..9badd41
--- /dev/null
+++ b/android-35/java/util/stream/Stream.java
@@ -0,0 +1,1683 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.UnaryOperator;
+
+/**
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>In addition to {@code Stream}, which is a stream of object references,
+ * there are primitive specializations for {@link IntStream}, {@link LongStream},
+ * and {@link DoubleStream}, all of which are referred to as "streams" and
+ * conform to the characteristics and restrictions described here.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>A stream implementation is permitted significant latitude in optimizing
+ * the computation of the result.  For example, a stream implementation is free
+ * to elide operations (or entire stages) from a stream pipeline -- and
+ * therefore elide invocation of behavioral parameters -- if it can prove that
+ * it would not affect the result of the computation.  This means that
+ * side-effects of behavioral parameters may not always be executed and should
+ * not be relied upon, unless otherwise specified (such as by the terminal
+ * operations {@code forEach} and {@code forEachOrdered}). (For a specific
+ * example of such an optimization, see the API note documented on the
+ * {@link #count} operation.  For more detail, see the
+ * <a href="package-summary.html#SideEffects">side-effects</a> section of the
+ * stream package documentation.)
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  To preserve correct behavior,
+ * these <em>behavioral parameters</em>:
+ * <ul>
+ * <li>must be <a href="package-summary.html#NonInterference">non-interfering</a>
+ * (they do not modify the stream source); and</li>
+ * <li>in most cases must be <a href="package-summary.html#Statelessness">stateless</a>
+ * (their result should not depend on any state that might change during execution
+ * of the stream pipeline).</li>
+ * </ul>
+ *
+ * <p>Such parameters are always instances of a
+ * <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  Unless otherwise specified these parameters must be
+ * <em>non-null</em>.
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable}.
+ * Operating on a stream after it has been closed will throw {@link IllegalStateException}.
+ * Most stream instances do not actually need to be closed after use, as they
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. Generally, only streams whose source is an IO channel,
+ * such as those returned by {@link Files#lines(Path)}, will require closing. If a
+ * stream does require closing, it must be opened as a resource within a try-with-resources
+ * statement or similar control structure to ensure that it is closed promptly after its
+ * operations have completed.
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @since 1.8
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface Stream<T> extends BaseStream<T, Stream<T>> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    Stream<T> filter(Predicate<? super T> predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(ToIntFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(ToLongFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @apiNote
+     * The {@code flatMap()} operation has the effect of applying a one-to-many
+     * transformation to the elements of the stream, and then flattening the
+     * resulting elements into a new stream.
+     *
+     * <p><b>Examples.</b>
+     *
+     * <p>If {@code orders} is a stream of purchase orders, and each purchase
+     * order contains a collection of line items, then the following produces a
+     * stream containing all the line items in all the orders:
+     * <pre>{@code
+     *     orders.flatMap(order -> order.getLineItems().stream())...
+     * }</pre>
+     *
+     * <p>If {@code path} is the path to a file, then the following produces a
+     * stream of the {@code words} contained in that file:
+     * <pre>{@code
+     *     Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
+     *     Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
+     * }</pre>
+     * The {@code mapper} function passed to {@code flatMap} splits a line,
+     * using a simple regular expression, into an array of words, and then
+     * creates a stream of words from that array.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #mapMulti
+     */
+    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
+
+    /**
+     * Returns an {@code LongStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
+
+    /**
+     * Returns an {@code DoubleStream} consisting of the results of replacing
+     * each element of this stream with the contents of a mapped stream produced
+     * by applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have placed been into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
+
+    // THE EXAMPLES USED IN THE JAVADOC MUST BE IN SYNC WITH THEIR CORRESPONDING
+    // TEST IN test/jdk/java/util/stream/examples/JavadocExamples.java.
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with multiple elements, specifically zero or more elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain Consumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain Consumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMap flatMap} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with a {@code Consumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates a stream from the
+     * internal buffer. Finally, it returns this stream to {@code flatMap}.
+     *
+     * @apiNote
+     * This method is similar to {@link #flatMap flatMap} in that it applies a one-to-many
+     * transformation to the elements of the stream and flattens the result elements
+     * into a new stream. This method is preferable to {@code flatMap} in the following
+     * circumstances:
+     * <ul>
+     * <li>When replacing each stream element with a small (possibly zero) number of
+     * elements. Using this method avoids the overhead of creating a new Stream instance
+     * for every group of result elements, as required by {@code flatMap}.</li>
+     * <li>When it is easier to use an imperative approach for generating result
+     * elements than it is to return them in the form of a Stream.</li>
+     * </ul>
+     *
+     * <p>If a lambda expression is provided as the mapper function argument, additional type
+     * information may be necessary for proper inference of the element type {@code <R>} of
+     * the returned stream. This can be provided in the form of explicit type declarations for
+     * the lambda parameters or as an explicit type argument to the {@code mapMulti} call.
+     *
+     * <p><b>Examples</b>
+     *
+     * <p>Given a stream of {@code Number} objects, the following
+     * produces a list containing only the {@code Integer} objects:
+     * <pre>{@code
+     *     Stream<Number> numbers = ... ;
+     *     List<Integer> integers = numbers.<Integer>mapMulti((number, consumer) -> {
+     *             if (number instanceof Integer i)
+     *                 consumer.accept(i);
+     *         })
+     *         .collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>If we have an {@code Iterable<Object>} and need to recursively expand its elements
+     * that are themselves of type {@code Iterable}, we can use {@code mapMulti} as follows:
+     * <pre>{@code
+     * class C {
+     *     static void expandIterable(Object e, Consumer<Object> c) {
+     *         if (e instanceof Iterable<?> elements) {
+     *             for (Object ie : elements) {
+     *                 expandIterable(ie, c);
+     *             }
+     *         } else if (e != null) {
+     *             c.accept(e);
+     *         }
+     *     }
+     *
+     *     public static void main(String[] args) {
+     *         var nestedList = List.of(1, List.of(2, List.of(3, 4)), 5);
+     *         Stream<Object> expandedStream = nestedList.stream().mapMulti(C::expandIterable);
+     *     }
+     * }
+     * }</pre>
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see #flatMap flatMap
+     * @since 16
+     */
+    default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMap(e -> {
+            SpinedBuffer<R> buffer = new SpinedBuffer<>();
+            mapper.accept(e, buffer);
+            return StreamSupport.stream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of replacing each
+     * element of this stream with multiple elements, specifically zero or more
+     * elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain IntConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain IntConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMapToInt flatMapToInt} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with an {@code IntConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates an {@code IntStream} from
+     * the internal buffer. Finally, it returns this stream to {@code flatMapToInt}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see #mapMulti mapMulti
+     * @since 16
+     */
+    default IntStream mapMultiToInt(BiConsumer<? super T, ? super IntConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMapToInt(e -> {
+            SpinedBuffer.OfInt buffer = new SpinedBuffer.OfInt();
+            mapper.accept(e, buffer);
+            return StreamSupport.intStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of replacing each
+     * element of this stream with multiple elements, specifically zero or more
+     * elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain LongConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain LongConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMapToLong flatMapToLong} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with a {@code LongConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates a {@code LongStream} from
+     * the internal buffer. Finally, it returns this stream to {@code flatMapToLong}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see #mapMulti mapMulti
+     * @since 16
+     */
+    default LongStream mapMultiToLong(BiConsumer<? super T, ? super LongConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMapToLong(e -> {
+            SpinedBuffer.OfLong buffer = new SpinedBuffer.OfLong();
+            mapper.accept(e, buffer);
+            return StreamSupport.longStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of replacing each
+     * element of this stream with multiple elements, specifically zero or more
+     * elements.
+     * Replacement is performed by applying the provided mapping function to each
+     * element in conjunction with a {@linkplain DoubleConsumer consumer} argument
+     * that accepts replacement elements. The mapping function calls the consumer
+     * zero or more times to provide the replacement elements.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>If the {@linkplain DoubleConsumer consumer} argument is used outside the scope of
+     * its application to the mapping function, the results are undefined.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #flatMapToDouble flatMapToDouble} on this stream,
+     * passing a function that behaves as follows. First, it calls the mapper function
+     * with an {@code DoubleConsumer} that accumulates replacement elements into a newly created
+     * internal buffer. When the mapper function returns, it creates a {@code DoubleStream} from
+     * the internal buffer. Finally, it returns this stream to {@code flatMapToDouble}.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function that generates replacement elements
+     * @return the new stream
+     * @see #mapMulti mapMulti
+     * @since 16
+     */
+    default DoubleStream mapMultiToDouble(BiConsumer<? super T, ? super DoubleConsumer> mapper) {
+        Objects.requireNonNull(mapper);
+        return flatMapToDouble(e -> {
+            SpinedBuffer.OfDouble buffer = new SpinedBuffer.OfDouble();
+            mapper.accept(e, buffer);
+            return StreamSupport.doubleStream(buffer.spliterator(), false);
+        });
+    }
+
+    /**
+     * Returns a stream consisting of the distinct elements (according to
+     * {@link Object#equals(Object)}) of this stream.
+     *
+     * <p>For ordered streams, the selection of distinct elements is stable
+     * (for duplicated elements, the element appearing first in the encounter
+     * order is preserved.)  For unordered streams, no stability guarantees
+     * are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * Preserving stability for {@code distinct()} in parallel pipelines is
+     * relatively expensive (requires that the operation act as a full barrier,
+     * with substantial buffering overhead), and stability is often not needed.
+     * Using an unordered stream source (such as {@link #generate(Supplier)})
+     * or removing the ordering constraint with {@link #unordered()} may result
+     * in significantly more efficient execution for {@code distinct()} in parallel
+     * pipelines, if the semantics of your situation permit.  If consistency
+     * with encounter order is required, and you are experiencing poor performance
+     * or memory utilization with {@code distinct()} in parallel pipelines,
+     * switching to sequential execution with {@link #sequential()} may improve
+     * performance.
+     *
+     * @return the new stream
+     */
+    Stream<T> distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to natural order.  If the elements of this stream are not
+     * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
+     * when the terminal operation is executed.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    Stream<T> sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to the provided {@code Comparator}.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to be used to compare stream elements
+     * @return the new stream
+     */
+    Stream<T> sorted(Comparator<? super T> comparator);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     Stream.of("one", "two", "three", "four")
+     *         .filter(e -> e.length() > 3)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(String::toUpperCase)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>In cases where the stream implementation is able to optimize away the
+     * production of some or all the elements (such as with short-circuiting
+     * operations like {@code findFirst}, or in the example described in
+     * {@link #count}), the action will not be invoked for those elements.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *                 non-interfering</a> action to perform on the elements as
+     *                 they are consumed from the stream
+     * @return the new stream
+     */
+    Stream<T> peek(Consumer<? super T> action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    Stream<T> limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    Stream<T> skip(long n);
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the longest
+     * prefix of elements taken from this stream that match the given predicate.
+     * Otherwise returns, if this stream is unordered, a stream consisting of a
+     * subset of elements taken from this stream that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to take any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * takes all elements (the result is the same as the input), or if no
+     * elements of the stream match the given predicate then no elements are
+     * taken (the result is an empty stream).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code takeWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as {@link #generate(Supplier)}) or
+     * removing the ordering constraint with {@link #unordered()} may result in
+     * significant speedups of {@code takeWhile()} in parallel pipelines, if the
+     * semantics of your situation permit.  If consistency with encounter order
+     * is required, and you are experiencing poor performance or memory
+     * utilization with {@code takeWhile()} in parallel pipelines, switching to
+     * sequential execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default Stream<T> takeWhile(Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.stream(
+                new WhileOps.UnorderedWhileSpliterator.OfRef.Taking<>(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Returns, if this stream is ordered, a stream consisting of the remaining
+     * elements of this stream after dropping the longest prefix of elements
+     * that match the given predicate.  Otherwise returns, if this stream is
+     * unordered, a stream consisting of the remaining elements of this stream
+     * after dropping a subset of elements that match the given predicate.
+     *
+     * <p>If this stream is ordered then the longest prefix is a contiguous
+     * sequence of elements of this stream that match the given predicate.  The
+     * first element of the sequence is the first element of this stream, and
+     * the element immediately following the last element of the sequence does
+     * not match the given predicate.
+     *
+     * <p>If this stream is unordered, and some (but not all) elements of this
+     * stream match the given predicate, then the behavior of this operation is
+     * nondeterministic; it is free to drop any subset of matching elements
+     * (which includes the empty set).
+     *
+     * <p>Independent of whether this stream is ordered or unordered if all
+     * elements of this stream match the given predicate then this operation
+     * drops all elements (the result is an empty stream), or if no elements of
+     * the stream match the given predicate then no elements are dropped (the
+     * result is the same as the input).
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @implSpec
+     * The default implementation obtains the {@link #spliterator() spliterator}
+     * of this stream, wraps that spliterator so as to support the semantics
+     * of this operation on traversal, and returns a new stream associated with
+     * the wrapped spliterator.  The returned stream preserves the execution
+     * characteristics of this stream (namely parallel or sequential execution
+     * as per {@link #isParallel()}) but the wrapped spliterator may choose to
+     * not support splitting.  When the returned stream is closed, the close
+     * handlers for both the returned and this stream are invoked.
+     *
+     * @apiNote
+     * While {@code dropWhile()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel
+     * pipelines, since the operation is constrained to return not just any
+     * valid prefix, but the longest prefix of elements in the encounter order.
+     * Using an unordered stream source (such as {@link #generate(Supplier)}) or
+     * removing the ordering constraint with {@link #unordered()} may result in
+     * significant speedups of {@code dropWhile()} in parallel pipelines, if the
+     * semantics of your situation permit.  If consistency with encounter order
+     * is required, and you are experiencing poor performance or memory
+     * utilization with {@code dropWhile()} in parallel pipelines, switching to
+     * sequential execution with {@link #sequential()} may improve performance.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements to determine the longest
+     *                  prefix of elements.
+     * @return the new stream
+     * @since 9
+     */
+    default Stream<T> dropWhile(Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        // Reuses the unordered spliterator, which, when encounter is present,
+        // is safe to use as long as it configured not to split
+        return StreamSupport.stream(
+                new WhileOps.UnorderedWhileSpliterator.OfRef.Dropping<>(spliterator(), true, predicate),
+                isParallel()).onClose(this::close);
+    }
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic.
+     * For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(Consumer<? super T> action);
+
+    /**
+     * Performs an action for each element of this stream, in the encounter
+     * order of the stream if the stream has a defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>This operation processes the elements one at a time, in encounter
+     * order if one exists.  Performing the action for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * performing the action for subsequent elements, but for any given element,
+     * the action may be performed in whatever thread the library chooses.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(Consumer)
+     */
+    void forEachOrdered(Consumer<? super T> action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array, whose {@linkplain Class#getComponentType runtime component
+     * type} is {@code Object}, containing the elements of this stream
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing the elements of this stream, using the
+     * provided {@code generator} function to allocate the returned array, as
+     * well as any additional arrays that might be required for a partitioned
+     * execution or for resizing.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote
+     * The generator function takes an integer, which is the size of the
+     * desired array, and produces an array of the desired size.  This can be
+     * concisely expressed with an array constructor reference:
+     * <pre>{@code
+     *     Person[] men = people.stream()
+     *                          .filter(p -> p.getGender() == MALE)
+     *                          .toArray(Person[]::new);
+     * }</pre>
+     *
+     * @param <A> the component type of the resulting array
+     * @param generator a function which produces a new array of the desired
+     *                  type and the provided length
+     * @return an array containing the elements in this stream
+     * @throws ArrayStoreException if the runtime type of any element of this
+     *         stream is not assignable to the {@linkplain Class#getComponentType
+     *         runtime component type} of the generated array
+     */
+    <A> A[] toArray(IntFunction<A[]> generator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     T result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code t},
+     * {@code accumulator.apply(identity, t)} is equal to {@code t}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, average, and string concatenation are all special
+     * cases of reduction. Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return the result of the reduction
+     */
+    T reduce(T identity, BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code Optional} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     T result = null;
+     *     for (T element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? Optional.of(result) : Optional.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return an {@link Optional} describing the result of the reduction
+     * @throws NullPointerException if the result of the reduction is null
+     * @see #reduce(Object, BinaryOperator)
+     * @see #min(Comparator)
+     * @see #max(Comparator)
+     */
+    Optional<T> reduce(BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity, accumulation and
+     * combining functions.  This is equivalent to:
+     * <pre>{@code
+     *     U result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the combiner
+     * function.  This means that for all {@code u}, {@code combiner(identity, u)}
+     * is equal to {@code u}.  Additionally, the {@code combiner} function
+     * must be compatible with the {@code accumulator} function; for all
+     * {@code u} and {@code t}, the following must hold:
+     * <pre>{@code
+     *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Many reductions using this form can be represented more simply
+     * by an explicit combination of {@code map} and {@code reduce} operations.
+     * The {@code accumulator} function acts as a fused mapper and accumulator,
+     * which can sometimes be more efficient than separate mapping and reduction,
+     * such as when knowing the previously reduced value allows you to avoid
+     * some computation.
+     *
+     * @param <U> The type of the result
+     * @param identity the identity value for the combiner function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see #reduce(BinaryOperator)
+     * @see #reduce(Object, BinaryOperator)
+     */
+    <U> U reduce(U identity,
+                 BiFunction<U, ? super T, U> accumulator,
+                 BinaryOperator<U> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (T element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote There are many existing classes in the JDK whose signatures are
+     * well-suited for use with method references as arguments to {@code collect()}.
+     * For example, the following will accumulate strings into an {@code ArrayList}:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+     *                                                ArrayList::addAll);
+     * }</pre>
+     *
+     * <p>The following will take a stream of strings and concatenates them into a
+     * single string:
+     * <pre>{@code
+     *     String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
+     *                                          StringBuilder::append)
+     *                                 .toString();
+     * }</pre>
+     *
+     * @param <R> the type of the mutable result container
+     * @param supplier a function that creates a new mutable result container.
+     *                 For a parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that must fold an element into a result
+     *                    container.
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function that accepts two partial result containers
+     *                    and merges them, which must be compatible with the
+     *                    accumulator function.  The combiner function must fold
+     *                    the elements from the second result container into the
+     *                    first result container.
+     * @return the result of the reduction
+     */
+    <R> R collect(Supplier<R> supplier,
+                  BiConsumer<R, ? super T> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream using a
+     * {@code Collector}.  A {@code Collector}
+     * encapsulates the functions used as arguments to
+     * {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
+     * collection strategies and composition of collect operations such as
+     * multiple-level grouping or partitioning.
+     *
+     * <p>If the stream is parallel, and the {@code Collector}
+     * is {@link Collector.Characteristics#CONCURRENT concurrent}, and
+     * either the stream is unordered or the collector is
+     * {@link Collector.Characteristics#UNORDERED unordered},
+     * then a concurrent reduction will be performed (see {@link Collector} for
+     * details on concurrent reduction.)
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>When executed in parallel, multiple intermediate results may be
+     * instantiated, populated, and merged so as to maintain isolation of
+     * mutable data structures.  Therefore, even when executed in parallel
+     * with non-thread-safe data structures (such as {@code ArrayList}), no
+     * additional synchronization is needed for a parallel reduction.
+     *
+     * @apiNote
+     * The following will accumulate strings into a List:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by city:
+     * <pre>{@code
+     *     Map<String, List<Person>> peopleByCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by state and city,
+     * cascading two {@code Collector}s together:
+     * <pre>{@code
+     *     Map<String, Map<String, List<Person>>> peopleByStateAndCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getState,
+     *                                                      Collectors.groupingBy(Person::getCity)));
+     * }</pre>
+     *
+     * @param <R> the type of the result
+     * @param <A> the intermediate accumulation type of the {@code Collector}
+     * @param collector the {@code Collector} describing the reduction
+     * @return the result of the reduction
+     * @see #collect(Supplier, BiConsumer, BiConsumer)
+     * @see Collectors
+     */
+    <R, A> R collect(Collector<? super T, A, R> collector);
+
+    /**
+     * Accumulates the elements of this stream into a {@code List}. The elements in
+     * the list will be in this stream's encounter order, if one exists. The returned List
+     * is unmodifiable; calls to any mutator method will always cause
+     * {@code UnsupportedOperationException} to be thrown. There are no
+     * guarantees on the implementation type or serializability of the returned List.
+     *
+     * <p>The returned instance may be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
+     * Callers should make no assumptions about the identity of the returned instances.
+     * Identity-sensitive operations on these instances (reference equality ({@code ==}),
+     * identity hash code, and synchronization) are unreliable and should be avoided.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @apiNote If more control over the returned object is required, use
+     * {@link Collectors#toCollection(Supplier)}.
+     *
+     * @implSpec The implementation in this interface returns a List produced as if by the following:
+     * <pre>{@code
+     * Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
+     * }</pre>
+     *
+     * @implNote Most instances of Stream will override this method and provide an implementation
+     * that is highly optimized compared to the implementation in this interface.
+     *
+     * @return a List containing the stream elements
+     *
+     * @since 16
+     */
+    @SuppressWarnings("unchecked")
+    default List<T> toList() {
+        return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
+    }
+
+    /**
+     * Returns the minimum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the minimum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the minimum element is null
+     */
+    Optional<T> min(Comparator<? super T> comparator);
+
+    /**
+     * Returns the maximum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the maximum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the maximum element is null
+     */
+    Optional<T> max(Comparator<? super T> comparator);
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @apiNote
+     * An implementation may choose to not execute the stream pipeline (either
+     * sequentially or in parallel) if it is capable of computing the count
+     * directly from the stream source.  In such cases no source elements will
+     * be traversed and no intermediate operations will be evaluated.
+     * Behavioral parameters with side-effects, which are strongly discouraged
+     * except for harmless cases such as debugging, may be affected.  For
+     * example, consider the following stream:
+     * <pre>{@code
+     *     List<String> l = Arrays.asList("A", "B", "C", "D");
+     *     long count = l.stream().peek(System.out::println).count();
+     * }</pre>
+     * The number of elements covered by the stream source, a {@code List}, is
+     * known and the intermediate operation, {@code peek}, does not inject into
+     * or remove elements from the stream (as may be the case for
+     * {@code flatMap} or {@code filter} operations).  Thus the count is the
+     * size of the {@code List} and there is no need to execute the pipeline
+     * and, as a side-effect, print out the list elements.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns an {@link Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty.  If the stream has
+     * no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     */
+    Optional<T> findFirst();
+
+    /**
+     * Returns an {@link Optional} describing some element of the stream, or an
+     * empty {@code Optional} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code Optional} describing some element of this stream, or an
+     * empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     * @see #findFirst()
+     */
+    Optional<T> findAny();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code Stream}.
+     *
+     * @param <T> type of elements
+     * @return a stream builder
+     */
+    public static<T> Builder<T> builder() {
+        return new Streams.StreamBuilderImpl<>();
+    }
+
+    /**
+     * Returns an empty sequential {@code Stream}.
+     *
+     * @param <T> the type of stream elements
+     * @return an empty sequential stream
+     */
+    public static<T> Stream<T> empty() {
+        return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} containing a single element.
+     *
+     * @param t the single element
+     * @param <T> the type of stream elements
+     * @return a singleton sequential stream
+     */
+    public static<T> Stream<T> of(T t) {
+        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} containing a single element, if
+     * non-null, otherwise returns an empty {@code Stream}.
+     *
+     * @param t the single element
+     * @param <T> the type of stream elements
+     * @return a stream with a single element if the specified element
+     *         is non-null, otherwise an empty stream
+     * @since 9
+     */
+    public static<T> Stream<T> ofNullable(T t) {
+        return t == null ? Stream.empty()
+                         : StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param <T> the type of stream elements
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs") // Creating a stream from an array is safe
+    public static<T> Stream<T> of(T... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code Stream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code Stream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * <p>The action of applying {@code f} for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying {@code f} for subsequent elements.  For any given
+     * element the action may be performed in whatever thread the library
+     * chooses.
+     *
+     * @param <T> the type of stream elements
+     * @param seed the initial element
+     * @param f a function to be applied to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code Stream}
+     */
+    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
+        Objects.requireNonNull(f);
+        Spliterator<T> spliterator = new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE) {
+            T prev;
+            boolean started;
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+                T t;
+                if (started)
+                    t = f.apply(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+        };
+        return StreamSupport.stream(spliterator, false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code Stream} produced by iterative
+     * application of the given {@code next} function to an initial element,
+     * conditioned on satisfying the given {@code hasNext} predicate.  The
+     * stream terminates as soon as the {@code hasNext} predicate returns false.
+     *
+     * <p>{@code Stream.iterate} should produce the same sequence of elements as
+     * produced by the corresponding for-loop:
+     * <pre>{@code
+     *     for (T index=seed; hasNext.test(index); index = next.apply(index)) {
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * <p>The resulting sequence may be empty if the {@code hasNext} predicate
+     * does not hold on the seed value.  Otherwise the first element will be the
+     * supplied {@code seed} value, the next element (if present) will be the
+     * result of applying the {@code next} function to the {@code seed} value,
+     * and so on iteratively until the {@code hasNext} predicate indicates that
+     * the stream should terminate.
+     *
+     * <p>The action of applying the {@code hasNext} predicate to an element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * the action of applying the {@code next} function to that element.  The
+     * action of applying the {@code next} function for one element
+     * <i>happens-before</i> the action of applying the {@code hasNext}
+     * predicate for subsequent elements.  For any given element an action may
+     * be performed in whatever thread the library chooses.
+     *
+     * @param <T> the type of stream elements
+     * @param seed the initial element
+     * @param hasNext a predicate to apply to elements to determine when the
+     *                stream must terminate.
+     * @param next a function to be applied to the previous element to produce
+     *             a new element
+     * @return a new sequential {@code Stream}
+     * @since 9
+     */
+    public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
+        Objects.requireNonNull(next);
+        Objects.requireNonNull(hasNext);
+        Spliterator<T> spliterator = new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE,
+               Spliterator.ORDERED | Spliterator.IMMUTABLE) {
+            T prev;
+            boolean started, finished;
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return false;
+                T t;
+                if (started)
+                    t = next.apply(prev);
+                else {
+                    t = seed;
+                    started = true;
+                }
+                if (!hasNext.test(t)) {
+                    prev = null;
+                    finished = true;
+                    return false;
+                }
+                action.accept(prev = t);
+                return true;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+                if (finished)
+                    return;
+                finished = true;
+                T t = started ? next.apply(prev) : seed;
+                prev = null;
+                while (hasNext.test(t)) {
+                    action.accept(t);
+                    t = next.apply(t);
+                }
+            }
+        };
+        return StreamSupport.stream(spliterator, false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code Supplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param <T> the type of stream elements
+     * @param s the {@code Supplier} of generated elements
+     * @return a new infinite sequential unordered {@code Stream}
+     */
+    public static<T> Stream<T> generate(Supplier<? extends T> s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.stream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * <p>This method operates on the two input streams and binds each stream
+     * to its source.  As a result subsequent modifications to an input stream
+     * source may not be reflected in the concatenated stream result.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowError}.
+     *
+     * <p>Subsequent changes to the sequential/parallel execution mode of the
+     * returned stream are not guaranteed to be propagated to the input streams.
+     *
+     * @apiNote
+     * To preserve optimization opportunities this method binds each stream to
+     * its source and accepts only two streams as parameters.  For example, the
+     * exact size of the concatenated stream source can be computed if the exact
+     * size of each input stream source is known.
+     * To concatenate more streams without binding, or without nested calls to
+     * this method, try creating a stream of streams and flat-mapping with the
+     * identity function, for example:
+     * <pre>{@code
+     *     Stream<T> concat = Stream.of(s1, s2, s3, s4).flatMap(s -> s);
+     * }</pre>
+     *
+     * @param <T> The type of stream elements
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        @SuppressWarnings("unchecked")
+        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
+                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
+        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code Stream}.  This allows the creation of a
+     * {@code Stream} by generating elements individually and adding them to the
+     * {@code Builder} (without the copying overhead that comes from using
+     * an {@code ArrayList} as a temporary buffer.)
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * when the {@link #build()} method is called, which creates an ordered
+     * {@code Stream} whose elements are the elements that were added to the stream
+     * builder, in the order they were added.
+     *
+     * @param <T> the type of stream elements
+     * @see Stream#builder()
+     * @since 1.8
+     */
+    public interface Builder<T> extends Consumer<T> {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        @Override
+        void accept(T t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        default Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further attempts
+         * to operate on the builder after it has entered the built state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        Stream<T> build();
+
+    }
+}
diff --git a/android-35/java/util/stream/StreamOpFlag.java b/android-35/java/util/stream/StreamOpFlag.java
new file mode 100644
index 0000000..8580b7c
--- /dev/null
+++ b/android-35/java/util/stream/StreamOpFlag.java
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Spliterator;
+
+/**
+ * Flags corresponding to characteristics of streams and operations. Flags are
+ * utilized by the stream framework to control, specialize or optimize
+ * computation.
+ *
+ * <p>
+ * Stream flags may be used to describe characteristics of several different
+ * entities associated with streams: stream sources, intermediate operations,
+ * and terminal operations.  Not all stream flags are meaningful for all
+ * entities; the following table summarizes which flags are meaningful in what
+ * contexts:
+ *
+ * <div>
+ * <table class="borderless">
+ *   <caption>Type Characteristics</caption>
+ *   <thead class="tableSubHeadingColor">
+ *     <tr>
+ *       <th colspan="2">&nbsp;</th>
+ *       <th>{@code DISTINCT}</th>
+ *       <th>{@code SORTED}</th>
+ *       <th>{@code ORDERED}</th>
+ *       <th>{@code SIZED}</th>
+ *       <th>{@code SHORT_CIRCUIT}</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Stream source</th>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>N</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Intermediate operation</th>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PC</td>
+ *        <td>PI</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Terminal operation</th>
+ *        <td>N</td>
+ *        <td>N</td>
+ *        <td>PC</td>
+ *        <td>N</td>
+ *        <td>PI</td>
+ *      </tr>
+ *   </tbody>
+ *   <tfoot>
+ *       <tr>
+ *         <th class="tableSubHeadingColor" colspan="2">Legend</th>
+ *         <th colspan="6" rowspan="7">&nbsp;</th>
+ *       </tr>
+ *       <tr>
+ *         <th class="tableSubHeadingColor">Flag</th>
+ *         <th class="tableSubHeadingColor">Meaning</th>
+ *         <th colspan="6"></th>
+ *       </tr>
+ *       <tr><td>Y</td><td>Allowed</td></tr>
+ *       <tr><td>N</td><td>Invalid</td></tr>
+ *       <tr><td>P</td><td>Preserves</td></tr>
+ *       <tr><td>C</td><td>Clears</td></tr>
+ *       <tr><td>I</td><td>Injects</td></tr>
+ *   </tfoot>
+ * </table>
+ * </div>
+ *
+ * <p>In the above table, "PCI" means "may preserve, clear, or inject"; "PC"
+ * means "may preserve or clear", "PI" means "may preserve or inject", and "N"
+ * means "not valid".
+ *
+ * <p>Stream flags are represented by unioned bit sets, so that a single word
+ * may describe all the characteristics of a given stream entity, and that, for
+ * example, the flags for a stream source can be efficiently combined with the
+ * flags for later operations on that stream.
+ *
+ * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
+ * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
+ * produce a mask containing only the valid flags for that entity type.
+ *
+ * <p>When describing a stream source, one only need describe what
+ * characteristics that stream has; when describing a stream operation, one need
+ * describe whether the operation preserves, injects, or clears that
+ * characteristic.  Accordingly, two bits are used for each flag, so as to allow
+ * representing not only the presence of a characteristic, but how an
+ * operation modifies that characteristic.  There are two common forms in which
+ * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
+ * are a unioned bit set constructed by ORing the enum characteristic values of
+ * {@link #set()} (or, more commonly, ORing the corresponding static named
+ * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
+ * bit set constructed by ORing the enum characteristic values of {@link #set()}
+ * or {@link #clear()} (to inject, or clear, respectively, the corresponding
+ * flag), or more commonly ORing the corresponding named constants prefixed with
+ * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
+ * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
+ * combining bitsets that the correct combining operations are applied in the
+ * correct order.
+ *
+ * <p>
+ * With the exception of {@link #SHORT_CIRCUIT}, stream characteristics can be
+ * derived from the equivalent {@link java.util.Spliterator} characteristics:
+ * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
+ * {@link java.util.Spliterator#ORDERED}, and
+ * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
+ * can be converted to stream flags using the method
+ * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
+ * {@link #toCharacteristics(int)}.  (The bit set
+ * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
+ * produce a valid spliterator characteristics bit set that can be converted to
+ * stream flags.)
+ *
+ * <p>
+ * The source of a stream encapsulates a spliterator. The characteristics of
+ * that source spliterator when transformed to stream flags will be a proper
+ * subset of stream flags of that stream.
+ * For example:
+ * <pre> {@code
+ *     Spliterator s = ...;
+ *     Stream stream = Streams.stream(s);
+ *     flagsFromSplitr = fromCharacteristics(s.characteristics());
+ *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
+ * }</pre>
+ *
+ * <p>
+ * An intermediate operation, performed on an input stream to create a new
+ * output stream, may preserve, clear or inject stream or operation
+ * characteristics.  Similarly, a terminal operation, performed on an input
+ * stream to produce an output result may preserve, clear or inject stream or
+ * operation characteristics.  Preservation means that if that characteristic
+ * is present on the input, then it is also present on the output.  Clearing
+ * means that the characteristic is not present on the output regardless of the
+ * input.  Injection means that the characteristic is present on the output
+ * regardless of the input.  If a characteristic is not cleared or injected then
+ * it is implicitly preserved.
+ *
+ * <p>
+ * A pipeline consists of a stream source encapsulating a spliterator, one or
+ * more intermediate operations, and finally a terminal operation that produces
+ * a result.  At each stage of the pipeline, a combined stream and operation
+ * flags can be calculated, using {@link #combineOpFlags(int, int)}.  Such flags
+ * ensure that preservation, clearing and injecting information is retained at
+ * each stage.
+ *
+ * The combined stream and operation flags for the source stage of the pipeline
+ * is calculated as follows:
+ * <pre> {@code
+ *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
+ * }</pre>
+ *
+ * The combined stream and operation flags of each subsequent intermediate
+ * operation stage in the pipeline is calculated as follows:
+ * <pre> {@code
+ *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
+ * }</pre>
+ *
+ * Finally the flags output from the last intermediate operation of the pipeline
+ * are combined with the operation flags of the terminal operation to produce
+ * the flags output from the pipeline.
+ *
+ * <p>Those flags can then be used to apply optimizations. For example, if
+ * {@code SIZED.isKnown(flags)} returns true then the stream size remains
+ * constant throughout the pipeline, this information can be utilized to
+ * pre-allocate data structures and combined with
+ * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
+ * perform concurrent in-place updates into a shared array.
+ *
+ * For specific details see the {@link AbstractPipeline} constructors.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamOpFlag {
+
+    /*
+     * Each characteristic takes up 2 bits in a bit set to accommodate
+     * preserving, clearing and setting/injecting information.
+     *
+     * This applies to stream flags, intermediate/terminal operation flags, and
+     * combined stream and operation flags. Even though the former only requires
+     * 1 bit of information per characteristic, is it more efficient when
+     * combining flags to align set and inject bits.
+     *
+     * Characteristics belong to certain types, see the Type enum. Bit masks for
+     * the types are constructed as per the following table:
+     *
+     *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
+     *          SPLITERATOR      01       01       01      01        00
+     *               STREAM      01       01       01      01        00
+     *                   OP      11       11       11      10        01
+     *          TERMINAL_OP      00       00       10      00        01
+     * UPSTREAM_TERMINAL_OP      00       00       10      00        00
+     *
+     * 01 = set/inject
+     * 10 = clear
+     * 11 = preserve
+     *
+     * Construction of the columns is performed using a simple builder for
+     * non-zero values.
+     */
+
+
+    // The following flags correspond to characteristics on Spliterator
+    // and the values MUST be equal.
+    //
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
+     * <p>
+     * A stream may have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     */
+    // 0, 0x00000001
+    // Matches Spliterator.DISTINCT
+    DISTINCT(0,
+             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that encounter order follows a natural
+     * sort order of comparable elements.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     * <p>
+     * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
+     * a sort order with an associated non-null comparator.  Augmenting flag
+     * state with addition properties such that those properties can be passed
+     * to operations requires some disruptive changes for a singular use-case.
+     * Furthermore, comparing comparators for equality beyond that of identity
+     * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
+     * for a defined non-natural sort order is not mapped internally to the
+     * {@code SORTED} flag.
+     */
+    // 1, 0x00000004
+    // Matches Spliterator.SORTED
+    SORTED(1,
+           set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that an encounter order is
+     * defined for stream elements.
+     * <p>
+     * A stream can have this value, an intermediate operation can preserve,
+     * clear or inject this value, or a terminal operation can preserve or clear
+     * this value.
+     */
+    // 2, 0x00000010
+    // Matches Spliterator.ORDERED
+    ORDERED(2,
+            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
+                    .clear(Type.UPSTREAM_TERMINAL_OP)),
+
+    /**
+     * Characteristic value signifying that size of the stream
+     * is of a known finite size that is equal to the known finite
+     * size of the source spliterator input to the first stream
+     * in the pipeline.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve or
+     * clear this value.
+     */
+    // 3, 0x00000040
+    // Matches Spliterator.SIZED
+    SIZED(3,
+          set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
+
+    // The following Spliterator characteristics are not currently used but a
+    // gap in the bit set is deliberately retained to enable corresponding
+    // stream flags if//when required without modification to other flag values.
+    //
+    // 4, 0x00000100 NONNULL(4, ...
+    // 5, 0x00000400 IMMUTABLE(5, ...
+    // 6, 0x00001000 CONCURRENT(6, ...
+    // 7, 0x00004000 SUBSIZED(7, ...
+
+    // The following 4 flags are currently undefined and a free for any further
+    // spliterator characteristics.
+    //
+    //  8, 0x00010000
+    //  9, 0x00040000
+    // 10, 0x00100000
+    // 11, 0x00400000
+
+    // The following flags are specific to streams and operations
+    //
+
+    /**
+     * Characteristic value signifying that an operation may short-circuit the
+     * stream.
+     * <p>
+     * An intermediate operation can preserve or inject this value,
+     * or a terminal operation can preserve or inject this value.
+     */
+    // 12, 0x01000000
+    SHORT_CIRCUIT(12,
+                  set(Type.OP).set(Type.TERMINAL_OP)),
+
+    /**
+     * Characteristic value signifying that an operation may adjust the
+     * total size of the stream.
+     * <p>
+     * The flag, if present, is only valid when SIZED is present;
+     * and is only valid for sequential streams.
+     * <p>
+     * An intermediate operation can preserve or inject this value.
+     */
+    // 13, 0x04000000
+    SIZE_ADJUSTING(13,
+                   set(Type.OP));
+
+    // The following 2 flags are currently undefined and a free for any further
+    // stream flags if/when required
+    //
+    // 14, 0x10000000
+    // 15, 0x40000000
+
+    /**
+     * Type of a flag
+     */
+    enum Type {
+        /**
+         * The flag is associated with spliterator characteristics.
+         */
+        SPLITERATOR,
+
+        /**
+         * The flag is associated with stream flags.
+         */
+        STREAM,
+
+        /**
+         * The flag is associated with intermediate operation flags.
+         */
+        OP,
+
+        /**
+         * The flag is associated with terminal operation flags.
+         */
+        TERMINAL_OP,
+
+        /**
+         * The flag is associated with terminal operation flags that are
+         * propagated upstream across the last stateful operation boundary
+         */
+        UPSTREAM_TERMINAL_OP
+    }
+
+    /**
+     * The bit pattern for setting/injecting a flag.
+     */
+    private static final int SET_BITS = 0b01;
+
+    /**
+     * The bit pattern for clearing a flag.
+     */
+    private static final int CLEAR_BITS = 0b10;
+
+    /**
+     * The bit pattern for preserving a flag.
+     */
+    private static final int PRESERVE_BITS = 0b11;
+
+    private static MaskBuilder set(Type t) {
+        return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
+    }
+
+    private static class MaskBuilder {
+        final Map<Type, Integer> map;
+
+        MaskBuilder(Map<Type, Integer> map) {
+            this.map = map;
+        }
+
+        MaskBuilder mask(Type t, Integer i) {
+            map.put(t, i);
+            return this;
+        }
+
+        MaskBuilder set(Type t) {
+            return mask(t, SET_BITS);
+        }
+
+        MaskBuilder clear(Type t) {
+            return mask(t, CLEAR_BITS);
+        }
+
+        MaskBuilder setAndClear(Type t) {
+            return mask(t, PRESERVE_BITS);
+        }
+
+        Map<Type, Integer> build() {
+            for (Type t : Type.values()) {
+                map.putIfAbsent(t, 0b00);
+            }
+            return map;
+        }
+    }
+
+    /**
+     * The mask table for a flag, this is used to determine if a flag
+     * corresponds to a certain flag type and for creating mask constants.
+     */
+    private final Map<Type, Integer> maskTable;
+
+    /**
+     * The bit position in the bit mask.
+     */
+    private final int bitPosition;
+
+    /**
+     * The set 2 bit set offset at the bit position.
+     */
+    private final int set;
+
+    /**
+     * The clear 2 bit set offset at the bit position.
+     */
+    private final int clear;
+
+    /**
+     * The preserve 2 bit set offset at the bit position.
+     */
+    private final int preserve;
+
+    private StreamOpFlag(int position, MaskBuilder maskBuilder) {
+        this.maskTable = maskBuilder.build();
+        // Two bits per flag
+        position *= 2;
+        this.bitPosition = position;
+        this.set = SET_BITS << position;
+        this.clear = CLEAR_BITS << position;
+        this.preserve = PRESERVE_BITS << position;
+    }
+
+    /**
+     * Gets the bitmap associated with setting this characteristic.
+     *
+     * @return the bitmap for setting this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int set() {
+        return set;
+    }
+
+    /**
+     * Gets the bitmap associated with clearing this characteristic.
+     *
+     * @return the bitmap for clearing this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int clear() {
+        return clear;
+    }
+
+    /**
+     * Determines if this flag is a stream-based flag.
+     *
+     * @return true if a stream-based flag, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isStreamFlag() {
+        return maskTable.get(Type.STREAM) > 0;
+    }
+
+    /**
+     * Checks if this flag is set on stream flags, injected on operation flags,
+     * and injected on combined stream and operation flags.
+     *
+     * @param flags the stream flags, operation flags, or combined stream and
+     *        operation flags
+     * @return true if this flag is known, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isKnown(int flags) {
+        return (flags & preserve) == set;
+    }
+
+    /**
+     * Checks if this flag is cleared on operation flags or combined stream and
+     * operation flags.
+     *
+     * @param flags the operation flags or combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isCleared(int flags) {
+        return (flags & preserve) == clear;
+    }
+
+    /**
+     * Checks if this flag is preserved on combined stream and operation flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isPreserved(int flags) {
+        return (flags & preserve) == preserve;
+    }
+
+    /**
+     * Determines if this flag can be set for a flag type.
+     *
+     * @param t the flag type.
+     * @return true if this flag can be set for the flag type, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean canSet(Type t) {
+        return (maskTable.get(t) & SET_BITS) > 0;
+    }
+
+    /**
+     * The bit mask for spliterator characteristics
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
+
+    /**
+     * The bit mask for source stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int STREAM_MASK = createMask(Type.STREAM);
+
+    /**
+     * The bit mask for intermediate operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int OP_MASK = createMask(Type.OP);
+
+    /**
+     * The bit mask for terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
+
+    /**
+     * The bit mask for upstream terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
+
+    private static int createMask(Type t) {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.maskTable.get(t) << flag.bitPosition;
+        }
+        return mask;
+    }
+
+    /**
+     * Complete flag mask.
+     */
+    private static final int FLAG_MASK = createFlagMask();
+
+    private static int createFlagMask() {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.preserve;
+        }
+        return mask;
+    }
+
+    /**
+     * Flag mask for stream flags that are set.
+     */
+    private static final int FLAG_MASK_IS = STREAM_MASK;
+
+    /**
+     * Flag mask for stream flags that are cleared.
+     */
+    private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
+
+    /**
+     * The initial value to be combined with the stream flags of the first
+     * stream in the pipeline.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
+
+    /**
+     * The bit value to set or inject {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_DISTINCT = DISTINCT.set;
+
+    /**
+     * The bit value to clear {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_DISTINCT = DISTINCT.clear;
+
+    /**
+     * The bit value to set or inject {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SORTED = SORTED.set;
+
+    /**
+     * The bit value to clear {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SORTED = SORTED.clear;
+
+    /**
+     * The bit value to set or inject {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_ORDERED = ORDERED.set;
+
+    /**
+     * The bit value to clear {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_ORDERED = ORDERED.clear;
+
+    /**
+     * The bit value to set {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SIZED = SIZED.set;
+
+    /**
+     * The bit value to clear {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SIZED = SIZED.clear;
+
+    /**
+     * The bit value to inject {@link #SHORT_CIRCUIT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
+
+    /**
+     * The bit value to inject {@link #SIZE_ADJUSTING}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SIZE_ADJUSTING = SIZE_ADJUSTING.set;
+
+    private static int getMask(int flags) {
+        return (flags == 0)
+               ? FLAG_MASK
+               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
+    }
+
+    /**
+     * Combines stream or operation flags with previously combined stream and
+     * operation flags to produce updated combined stream and operation flags.
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and injected combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on the stream flags or injected on operation flags,
+     * and preserved on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and injected on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag cleared on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag preserved on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * @param newStreamOrOpFlags the stream or operation flags.
+     * @param prevCombOpFlags previously combined stream and operation flags.
+     *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
+     * @return the updated combined stream and operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
+        // 0x01 or 0x10 nibbles are transformed to 0x11
+        // 0x00 nibbles remain unchanged
+        // Then all the bits are flipped
+        // Then the result is logically or'ed with the operation flags.
+        return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
+    }
+
+    /**
+     * Converts combined stream and operation flags to stream flags.
+     *
+     * <p>Each flag injected on the combined stream and operation flags will be
+     * set on the stream flags.
+     *
+     * @param combOpFlags the combined stream and operation flags.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toStreamFlags(int combOpFlags) {
+        // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
+        // Shift left 1 to restore set flags and mask off anything other than the set flags
+        return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
+    }
+
+    /**
+     * Converts stream flags to a spliterator characteristic bit set.
+     *
+     * @param streamFlags the stream flags.
+     * @return the spliterator characteristic bit set.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toCharacteristics(int streamFlags) {
+        return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @implSpec
+     * If the spliterator is naturally {@code SORTED} (the associated
+     * {@code Comparator} is {@code null}) then the characteristic is converted
+     * to the {@link #SORTED} flag, otherwise the characteristic is not
+     * converted.
+     *
+     * @param spliterator the spliterator from which to obtain characteristic
+     *        bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(Spliterator<?> spliterator) {
+        int characteristics = spliterator.characteristics();
+        if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
+            // Do not propagate the SORTED characteristic if it does not correspond
+            // to a natural sort order
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
+        }
+        else {
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+        }
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @param characteristics the spliterator characteristic bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(int characteristics) {
+        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+}
diff --git a/android-35/java/util/stream/StreamShape.java b/android-35/java/util/stream/StreamShape.java
new file mode 100644
index 0000000..5bcae4a
--- /dev/null
+++ b/android-35/java/util/stream/StreamShape.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An enum describing the known shape specializations for stream abstractions.
+ * Each will correspond to a specific subinterface of {@link BaseStream}
+ * (e.g., {@code REFERENCE} corresponds to {@code Stream}, {@code INT_VALUE}
+ * corresponds to {@code IntStream}).  Each may also correspond to
+ * specializations of value-handling abstractions such as {@code Spliterator},
+ * {@code Consumer}, etc.
+ *
+ * @apiNote
+ * This enum is used by implementations to determine compatibility between
+ * streams and operations (i.e., if the output shape of a stream is compatible
+ * with the input shape of the next operation).
+ *
+ * <p>Some APIs require you to specify both a generic type and a stream shape
+ * for input or output elements, such as {@link TerminalOp} which has both
+ * generic type parameters for its input types, and a getter for the
+ * input shape.  When representing primitive streams in this way, the
+ * generic type parameter should correspond to the wrapper type for that
+ * primitive type.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamShape {
+    /**
+     * The shape specialization corresponding to {@code Stream} and elements
+     * that are object references.
+     */
+    REFERENCE,
+    /**
+     * The shape specialization corresponding to {@code IntStream} and elements
+     * that are {@code int} values.
+     */
+    INT_VALUE,
+    /**
+     * The shape specialization corresponding to {@code LongStream} and elements
+     * that are {@code long} values.
+     */
+    LONG_VALUE,
+    /**
+     * The shape specialization corresponding to {@code DoubleStream} and
+     * elements that are {@code double} values.
+     */
+    DOUBLE_VALUE
+}
diff --git a/android-35/java/util/stream/StreamSpliterators.java b/android-35/java/util/stream/StreamSpliterators.java
new file mode 100644
index 0000000..01ba72d
--- /dev/null
+++ b/android-35/java/util/stream/StreamSpliterators.java
@@ -0,0 +1,1550 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+/**
+ * Spliterator implementations for wrapping and delegating spliterators, used
+ * in the implementation of the {@link Stream#spliterator()} method.
+ *
+ * @since 1.8
+ */
+class StreamSpliterators {
+
+    /**
+     * Abstract wrapping spliterator that binds to the spliterator of a
+     * pipeline helper on first operation.
+     *
+     * <p>This spliterator is not late-binding and will bind to the source
+     * spliterator when first operated on.
+     *
+     * <p>A wrapping spliterator produced from a sequential stream
+     * cannot be split if there are stateful operations present.
+     */
+    private abstract static class AbstractWrappingSpliterator<P_IN, P_OUT,
+                                                              T_BUFFER extends AbstractSpinedBuffer>
+            implements Spliterator<P_OUT> {
+
+        // @@@ Detect if stateful operations are present or not
+        //     If not then can split otherwise cannot
+
+        /**
+         * True if this spliterator supports splitting
+         */
+        final boolean isParallel;
+
+        final PipelineHelper<P_OUT> ph;
+
+        /**
+         * Supplier for the source spliterator.  Client provides either a
+         * spliterator or a supplier.
+         */
+        private Supplier<Spliterator<P_IN>> spliteratorSupplier;
+
+        /**
+         * Source spliterator.  Either provided from client or obtained from
+         * supplier.
+         */
+        Spliterator<P_IN> spliterator;
+
+        /**
+         * Sink chain for the downstream stages of the pipeline, ultimately
+         * leading to the buffer. Used during partial traversal.
+         */
+        Sink<P_IN> bufferSink;
+
+        /**
+         * A function that advances one element of the spliterator, pushing
+         * it to bufferSink.  Returns whether any elements were processed.
+         * Used during partial traversal.
+         */
+        BooleanSupplier pusher;
+
+        /** Next element to consume from the buffer, used during partial traversal */
+        long nextToConsume;
+
+        /** Buffer into which elements are pushed.  Used during partial traversal. */
+        T_BUFFER buffer;
+
+        /**
+         * True if full traversal has occurred (with possible cancellation).
+         * If doing a partial traversal, there may be still elements in buffer.
+         */
+        boolean finished;
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Supplier<Spliterator>}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Supplier<Spliterator<P_IN>> spliteratorSupplier,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = spliteratorSupplier;
+            this.spliterator = null;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Spliterator}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Spliterator<P_IN> spliterator,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = null;
+            this.spliterator = spliterator;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Called before advancing to set up spliterator, if needed.
+         */
+        final void init() {
+            if (spliterator == null) {
+                spliterator = spliteratorSupplier.get();
+                spliteratorSupplier = null;
+            }
+        }
+
+        /**
+         * Get an element from the source, pushing it into the sink chain,
+         * setting up the buffer if needed
+         * @return whether there are elements to consume from the buffer
+         */
+        final boolean doAdvance() {
+            if (buffer == null) {
+                if (finished)
+                    return false;
+
+                init();
+                initPartialTraversalState();
+                nextToConsume = 0;
+                bufferSink.begin(spliterator.getExactSizeIfKnown());
+                return fillBuffer();
+            }
+            else {
+                ++nextToConsume;
+                boolean hasNext = nextToConsume < buffer.count();
+                if (!hasNext) {
+                    nextToConsume = 0;
+                    buffer.clear();
+                    hasNext = fillBuffer();
+                }
+                return hasNext;
+            }
+        }
+
+        /**
+         * Invokes the shape-specific constructor with the provided arguments
+         * and returns the result.
+         */
+        abstract AbstractWrappingSpliterator<P_IN, P_OUT, ?> wrap(Spliterator<P_IN> s);
+
+        /**
+         * Initializes buffer, sink chain, and pusher for a shape-specific
+         * implementation.
+         */
+        abstract void initPartialTraversalState();
+
+        @Override
+        public Spliterator<P_OUT> trySplit() {
+            if (isParallel && buffer == null && !finished) {
+                init();
+
+                Spliterator<P_IN> split = spliterator.trySplit();
+                return (split == null) ? null : wrap(split);
+            }
+            else
+                return null;
+        }
+
+        /**
+         * If the buffer is empty, push elements into the sink chain until
+         * the source is empty or cancellation is requested.
+         * @return whether there are elements to consume from the buffer
+         */
+        private boolean fillBuffer() {
+            while (buffer.count() == 0) {
+                if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) {
+                    if (finished)
+                        return false;
+                    else {
+                        bufferSink.end(); // might trigger more elements
+                        finished = true;
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public final long estimateSize() {
+            long exactSizeIfKnown = getExactSizeIfKnown();
+            // Use the estimate of the wrapped spliterator
+            // Note this may not be accurate if there are filter/flatMap
+            // operations filtering or adding elements to the stream
+            return exactSizeIfKnown == -1 ? spliterator.estimateSize() : exactSizeIfKnown;
+        }
+
+        @Override
+        public final long getExactSizeIfKnown() {
+            init();
+            return ph.exactOutputSizeIfKnown(spliterator);
+        }
+
+        @Override
+        public final int characteristics() {
+            init();
+
+            // Get the characteristics from the pipeline
+            int c = StreamOpFlag.toCharacteristics(StreamOpFlag.toStreamFlags(ph.getStreamAndOpFlags()));
+
+            // Mask off the size and uniform characteristics and replace with
+            // those of the spliterator
+            // Note that a non-uniform spliterator can change from something
+            // with an exact size to an estimate for a sub-split, for example
+            // with HashSet where the size is known at the top level spliterator
+            // but for sub-splits only an estimate is known
+            if ((c & Spliterator.SIZED) != 0) {
+                c &= ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+                c |= (spliterator.characteristics() & (Spliterator.SIZED | Spliterator.SUBSIZED));
+            }
+
+            return c;
+        }
+
+        @Override
+        public Comparator<? super P_OUT> getComparator() {
+            if (!hasCharacteristics(SORTED))
+                throw new IllegalStateException();
+            return null;
+        }
+
+        @Override
+        public final String toString() {
+            return String.format("%s[%s]", getClass().getName(), spliterator);
+        }
+    }
+
+    static final class WrappingSpliterator<P_IN, P_OUT>
+            extends AbstractWrappingSpliterator<P_IN, P_OUT, SpinedBuffer<P_OUT>> {
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Supplier<Spliterator<P_IN>> supplier,
+                            boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Spliterator<P_IN> spliterator,
+                            boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        WrappingSpliterator<P_IN, P_OUT> wrap(Spliterator<P_IN> s) {
+            return new WrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer<P_OUT> b = new SpinedBuffer<>();
+            buffer = b;
+            bufferSink = ph.wrapSink(b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super P_OUT> consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super P_OUT> consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink<P_OUT>) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class IntWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Integer, SpinedBuffer.OfInt>
+            implements Spliterator.OfInt {
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Supplier<Spliterator<P_IN>> supplier,
+                               boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Spliterator<P_IN> spliterator,
+                               boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Integer, ?> wrap(Spliterator<P_IN> s) {
+            return new IntWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfInt b = new SpinedBuffer.OfInt();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfInt) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            return (Spliterator.OfInt) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfInt) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class LongWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Long, SpinedBuffer.OfLong>
+            implements Spliterator.OfLong {
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Supplier<Spliterator<P_IN>> supplier,
+                                boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Spliterator<P_IN> spliterator,
+                                boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Long, ?> wrap(Spliterator<P_IN> s) {
+            return new LongWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfLong b = new SpinedBuffer.OfLong();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfLong) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            return (Spliterator.OfLong) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfLong) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class DoubleWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Double, SpinedBuffer.OfDouble>
+            implements Spliterator.OfDouble {
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Supplier<Spliterator<P_IN>> supplier,
+                                  boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Spliterator<P_IN> spliterator,
+                                  boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Double, ?> wrap(Spliterator<P_IN> s) {
+            return new DoubleWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfDouble b = new SpinedBuffer.OfDouble();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfDouble) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            return (Spliterator.OfDouble) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfDouble) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    /**
+     * Spliterator implementation that delegates to an underlying spliterator,
+     * acquiring the spliterator from a {@code Supplier<Spliterator>} on the
+     * first call to any spliterator method.
+     * @param <T>
+     */
+    static class DelegatingSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        private final Supplier<? extends T_SPLITR> supplier;
+
+        private T_SPLITR s;
+
+        DelegatingSpliterator(Supplier<? extends T_SPLITR> supplier) {
+            this.supplier = supplier;
+        }
+
+        T_SPLITR get() {
+            if (s == null) {
+                s = supplier.get();
+            }
+            return s;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T_SPLITR trySplit() {
+            return (T_SPLITR) get().trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            return get().tryAdvance(consumer);
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            get().forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            return get().estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return get().characteristics();
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return get().getComparator();
+        }
+
+        @Override
+        public long getExactSizeIfKnown() {
+            return get().getExactSizeIfKnown();
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName() + "[" + get() + "]";
+        }
+
+        static class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends DelegatingSpliterator<T, T_SPLITR>
+            implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(Supplier<? extends T_SPLITR> supplier) {
+                super(supplier);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                return get().tryAdvance(consumer);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                get().forEachRemaining(consumer);
+            }
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Supplier<Spliterator.OfInt> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Supplier<Spliterator.OfLong> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Supplier<Spliterator.OfDouble> supplier) {
+                super(supplier);
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator from a source Spliterator that reports
+     * {@code SUBSIZED}.
+     *
+     */
+    abstract static class SliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        // The start index of the slice
+        final long sliceOrigin;
+        // One past the last index of the slice
+        final long sliceFence;
+
+        // The spliterator to slice
+        T_SPLITR s;
+        // current (absolute) index, modified on advance/split
+        long index;
+        // one past last (absolute) index or sliceFence, which ever is smaller
+        long fence;
+
+        SliceSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence) {
+            assert s.hasCharacteristics(Spliterator.SUBSIZED);
+            this.s = s;
+            this.sliceOrigin = sliceOrigin;
+            this.sliceFence = sliceFence;
+            this.index = origin;
+            this.fence = fence;
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence);
+
+        public T_SPLITR trySplit() {
+            if (sliceOrigin >= fence)
+                return null;
+
+            if (index >= fence)
+                return null;
+
+            // Keep splitting until the left and right splits intersect with the slice
+            // thereby ensuring the size estimate decreases.
+            // This also avoids creating empty spliterators which can result in
+            // existing and additionally created F/J tasks that perform
+            // redundant work on no elements.
+            while (true) {
+                @SuppressWarnings("unchecked")
+                T_SPLITR leftSplit = (T_SPLITR) s.trySplit();
+                if (leftSplit == null)
+                    return null;
+
+                long leftSplitFenceUnbounded = index + leftSplit.estimateSize();
+                long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence);
+                if (sliceOrigin >= leftSplitFence) {
+                    // The left split does not intersect with, and is to the left of, the slice
+                    // The right split does intersect
+                    // Discard the left split and split further with the right split
+                    index = leftSplitFence;
+                }
+                else if (leftSplitFence >= sliceFence) {
+                    // The right split does not intersect with, and is to the right of, the slice
+                    // The left split does intersect
+                    // Discard the right split and split further with the left split
+                    s = leftSplit;
+                    fence = leftSplitFence;
+                }
+                else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) {
+                    // The left split is contained within the slice, return the underlying left split
+                    // Right split is contained within or intersects with the slice
+                    index = leftSplitFence;
+                    return leftSplit;
+                } else {
+                    // The left split intersects with the slice
+                    // Right split is contained within or intersects with the slice
+                    return makeSpliterator(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence);
+                }
+            }
+        }
+
+        public long estimateSize() {
+            return (sliceOrigin < fence)
+                   ? fence - Math.max(sliceOrigin, index) : 0;
+        }
+
+        public int characteristics() {
+            return s.characteristics();
+        }
+
+        static final class OfRef<T>
+                extends SliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T> {
+
+            OfRef(Spliterator<T> s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfRef(Spliterator<T> s,
+                          long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s,
+                                                     long sliceOrigin, long sliceFence,
+                                                     long origin, long fence) {
+                return new OfRef<>(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(e -> {});
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(e -> {});
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+        }
+
+        abstract static class OfPrimitive<T,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                T_CONS>
+                extends SliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(T_SPLITR s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfPrimitive(T_SPLITR s,
+                                long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(emptyConsumer());
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(emptyConsumer());
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+
+            protected abstract T_CONS emptyConsumer();
+        }
+
+        static final class OfInt extends OfPrimitive<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfInt(Spliterator.OfInt s,
+                  long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s,
+                                                        long sliceOrigin, long sliceFence,
+                                                        long origin, long fence) {
+                return new SliceSpliterator.OfInt(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected IntConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfLong(Spliterator.OfLong s,
+                   long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s,
+                                                         long sliceOrigin, long sliceFence,
+                                                         long origin, long fence) {
+                return new SliceSpliterator.OfLong(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected LongConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfDouble(Spliterator.OfDouble s,
+                     long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s,
+                                                           long sliceOrigin, long sliceFence,
+                                                           long origin, long fence) {
+                return new SliceSpliterator.OfDouble(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected DoubleConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator that does not preserve order, if any, of a source
+     * Spliterator.
+     *
+     * Note: The source spliterator may report {@code ORDERED} since that
+     * spliterator be the result of a previous pipeline stage that was
+     * collected to a {@code Node}. It is the order of the pipeline stage
+     * that governs whether this slice spliterator is to be used or not.
+     */
+    abstract static class UnorderedSliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        static final int CHUNK_SIZE = 1 << 7;
+
+        // The spliterator to slice
+        protected final T_SPLITR s;
+        protected final boolean unlimited;
+        protected final int chunkSize;
+        private final long skipThreshold;
+        private final AtomicLong permits;
+
+        UnorderedSliceSpliterator(T_SPLITR s, long skip, long limit) {
+            this.s = s;
+            this.unlimited = limit < 0;
+            this.skipThreshold = limit >= 0 ? limit : 0;
+            this.chunkSize = limit >= 0 ? (int)Math.min(CHUNK_SIZE,
+                                                        ((skip + limit) / AbstractTask.getLeafTarget()) + 1) : CHUNK_SIZE;
+            this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip);
+        }
+
+        UnorderedSliceSpliterator(T_SPLITR s,
+                                  UnorderedSliceSpliterator<T, T_SPLITR> parent) {
+            this.s = s;
+            this.unlimited = parent.unlimited;
+            this.permits = parent.permits;
+            this.skipThreshold = parent.skipThreshold;
+            this.chunkSize = parent.chunkSize;
+        }
+
+        /**
+         * Acquire permission to skip or process elements.  The caller must
+         * first acquire the elements, then consult this method for guidance
+         * as to what to do with the data.
+         *
+         * <p>We use an {@code AtomicLong} to atomically maintain a counter,
+         * which is initialized as skip+limit if we are limiting, or skip only
+         * if we are not limiting.  The user should consult the method
+         * {@code checkPermits()} before acquiring data elements.
+         *
+         * @param numElements the number of elements the caller has in hand
+         * @return the number of elements that should be processed; any
+         * remaining elements should be discarded.
+         */
+        protected final long acquirePermits(long numElements) {
+            long remainingPermits;
+            long grabbing;
+            // permits never increase, and don't decrease below zero
+            assert numElements > 0;
+            do {
+                remainingPermits = permits.get();
+                if (remainingPermits == 0)
+                    return unlimited ? numElements : 0;
+                grabbing = Math.min(remainingPermits, numElements);
+            } while (grabbing > 0 &&
+                     !permits.compareAndSet(remainingPermits, remainingPermits - grabbing));
+
+            if (unlimited)
+                return Math.max(numElements - grabbing, 0);
+            else if (remainingPermits > skipThreshold)
+                return Math.max(grabbing - (remainingPermits - skipThreshold), 0);
+            else
+                return grabbing;
+        }
+
+        enum PermitStatus { NO_MORE, MAYBE_MORE, UNLIMITED }
+
+        /** Call to check if permits might be available before acquiring data */
+        protected final PermitStatus permitStatus() {
+            if (permits.get() > 0)
+                return PermitStatus.MAYBE_MORE;
+            else
+                return unlimited ?  PermitStatus.UNLIMITED : PermitStatus.NO_MORE;
+        }
+
+        public final T_SPLITR trySplit() {
+            // Stop splitting when there are no more limit permits
+            if (permits.get() == 0)
+                return null;
+            @SuppressWarnings("unchecked")
+            T_SPLITR split = (T_SPLITR) s.trySplit();
+            return split == null ? null : makeSpliterator(split);
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s);
+
+        public final long estimateSize() {
+            return s.estimateSize();
+        }
+
+        public final int characteristics() {
+            return s.characteristics() &
+                   ~(Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED);
+        }
+
+        static final class OfRef<T> extends UnorderedSliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T>, Consumer<T> {
+            T tmpSlot;
+
+            OfRef(Spliterator<T> s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfRef(Spliterator<T> s, OfRef<T> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public final void accept(T t) {
+                tmpSlot = t;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(this))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        action.accept(tmpSlot);
+                        tmpSlot = null;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                ArrayBuffer.OfRef<T> sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of chunkSize
+                        if (sb == null)
+                            sb = new ArrayBuffer.OfRef<>(chunkSize);
+                        else
+                            sb.reset();
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sb) && ++permitsRequested < chunkSize);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s) {
+                return new UnorderedSliceSpliterator.OfRef<>(s, this);
+            }
+        }
+
+        /**
+         * Concrete sub-types must also be an instance of type {@code T_CONS}.
+         *
+         * @param <T_BUFF> the type of the spined buffer. Must also be a type of
+         *        {@code T_CONS}.
+         */
+        abstract static class OfPrimitive<
+                T,
+                T_CONS,
+                T_BUFF extends ArrayBuffer.OfPrimitive<T_CONS>,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends UnorderedSliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(T_SPLITR s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfPrimitive(T_SPLITR s, UnorderedSliceSpliterator.OfPrimitive<T, T_CONS, T_BUFF, T_SPLITR> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+                @SuppressWarnings("unchecked")
+                T_CONS consumer = (T_CONS) this;
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(consumer))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        acceptConsumed(action);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            protected abstract void acceptConsumed(T_CONS action);
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                T_BUFF sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of chunkSize
+                        if (sb == null)
+                            sb = bufferCreate(chunkSize);
+                        else
+                            sb.reset();
+                        @SuppressWarnings("unchecked")
+                        T_CONS sbc = (T_CONS) sb;
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sbc) && ++permitsRequested < chunkSize);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            protected abstract T_BUFF bufferCreate(int initialCapacity);
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, ArrayBuffer.OfInt, Spliterator.OfInt>
+                implements Spliterator.OfInt, IntConsumer {
+
+            int tmpValue;
+
+            OfInt(Spliterator.OfInt s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfInt(Spliterator.OfInt s, UnorderedSliceSpliterator.OfInt parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(int value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(IntConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfInt bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfInt(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
+                return new UnorderedSliceSpliterator.OfInt(s, this);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, ArrayBuffer.OfLong, Spliterator.OfLong>
+                implements Spliterator.OfLong, LongConsumer {
+
+            long tmpValue;
+
+            OfLong(Spliterator.OfLong s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfLong(Spliterator.OfLong s, UnorderedSliceSpliterator.OfLong parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(long value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(LongConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfLong bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfLong(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
+                return new UnorderedSliceSpliterator.OfLong(s, this);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, ArrayBuffer.OfDouble, Spliterator.OfDouble>
+                implements Spliterator.OfDouble, DoubleConsumer {
+
+            double tmpValue;
+
+            OfDouble(Spliterator.OfDouble s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfDouble(Spliterator.OfDouble s, UnorderedSliceSpliterator.OfDouble parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(double value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(DoubleConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfDouble bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfDouble(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
+                return new UnorderedSliceSpliterator.OfDouble(s, this);
+            }
+        }
+    }
+
+    /**
+     * A wrapping spliterator that only reports distinct elements of the
+     * underlying spliterator. Does not preserve size and encounter order.
+     */
+    static final class DistinctSpliterator<T> implements Spliterator<T>, Consumer<T> {
+
+        // The value to represent null in the ConcurrentHashMap
+        private static final Object NULL_VALUE = new Object();
+
+        // The underlying spliterator
+        private final Spliterator<T> s;
+
+        // ConcurrentHashMap holding distinct elements as keys
+        private final ConcurrentHashMap<T, Boolean> seen;
+
+        // Temporary element, only used with tryAdvance
+        private T tmpSlot;
+
+        DistinctSpliterator(Spliterator<T> s) {
+            this(s, new ConcurrentHashMap<>());
+        }
+
+        private DistinctSpliterator(Spliterator<T> s, ConcurrentHashMap<T, Boolean> seen) {
+            this.s = s;
+            this.seen = seen;
+        }
+
+        @Override
+        public void accept(T t) {
+            this.tmpSlot = t;
+        }
+
+        @SuppressWarnings("unchecked")
+        private T mapNull(T t) {
+            return t != null ? t : (T) NULL_VALUE;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            while (s.tryAdvance(this)) {
+                if (seen.putIfAbsent(mapNull(tmpSlot), Boolean.TRUE) == null) {
+                    action.accept(tmpSlot);
+                    tmpSlot = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            s.forEachRemaining(t -> {
+                if (seen.putIfAbsent(mapNull(t), Boolean.TRUE) == null) {
+                    action.accept(t);
+                }
+            });
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            Spliterator<T> split = s.trySplit();
+            return (split != null) ? new DistinctSpliterator<>(split, seen) : null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return s.estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return (s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED |
+                                            Spliterator.SORTED | Spliterator.ORDERED))
+                   | Spliterator.DISTINCT;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return s.getComparator();
+        }
+    }
+
+    /**
+     * A Spliterator that infinitely supplies elements in no particular order.
+     *
+     * <p>Splitting divides the estimated size in two and stops when the
+     * estimate size is 0.
+     *
+     * <p>The {@code forEachRemaining} method if invoked will never terminate.
+     * The {@code tryAdvance} method always returns true.
+     *
+     */
+    abstract static class InfiniteSupplyingSpliterator<T> implements Spliterator<T> {
+        long estimate;
+
+        protected InfiniteSupplyingSpliterator(long estimate) {
+            this.estimate = estimate;
+        }
+
+        @Override
+        public long estimateSize() {
+            return estimate;
+        }
+
+        @Override
+        public int characteristics() {
+            return IMMUTABLE;
+        }
+
+        static final class OfRef<T> extends InfiniteSupplyingSpliterator<T> {
+            final Supplier<? extends T> s;
+
+            OfRef(long size, Supplier<? extends T> s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.get());
+                return true;
+            }
+
+            @Override
+            public Spliterator<T> trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfRef<>(estimate >>>= 1, s);
+            }
+        }
+
+        static final class OfInt extends InfiniteSupplyingSpliterator<Integer>
+                implements Spliterator.OfInt {
+            final IntSupplier s;
+
+            OfInt(long size, IntSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsInt());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfInt trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfInt(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfLong extends InfiniteSupplyingSpliterator<Long>
+                implements Spliterator.OfLong {
+            final LongSupplier s;
+
+            OfLong(long size, LongSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(LongConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsLong());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfLong trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfLong(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfDouble extends InfiniteSupplyingSpliterator<Double>
+                implements Spliterator.OfDouble {
+            final DoubleSupplier s;
+
+            OfDouble(long size, DoubleSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsDouble());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfDouble trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfDouble(estimate = estimate >>> 1, s);
+            }
+        }
+    }
+
+    // @@@ Consolidate with Node.Builder
+    abstract static class ArrayBuffer {
+        int index;
+
+        void reset() {
+            index = 0;
+        }
+
+        static final class OfRef<T> extends ArrayBuffer implements Consumer<T> {
+            final Object[] array;
+
+            OfRef(int size) {
+                this.array = new Object[size];
+            }
+
+            @Override
+            public void accept(T t) {
+                array[index++] = t;
+            }
+
+            public void forEach(Consumer<? super T> action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    @SuppressWarnings("unchecked")
+                    T t = (T) array[i];
+                    action.accept(t);
+                }
+            }
+        }
+
+        abstract static class OfPrimitive<T_CONS> extends ArrayBuffer {
+            int index;
+
+            @Override
+            void reset() {
+                index = 0;
+            }
+
+            abstract void forEach(T_CONS action, long fence);
+        }
+
+        static final class OfInt extends OfPrimitive<IntConsumer>
+                implements IntConsumer {
+            final int[] array;
+
+            OfInt(int size) {
+                this.array = new int[size];
+            }
+
+            @Override
+            public void accept(int t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(IntConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<LongConsumer>
+                implements LongConsumer {
+            final long[] array;
+
+            OfLong(int size) {
+                this.array = new long[size];
+            }
+
+            @Override
+            public void accept(long t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(LongConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<DoubleConsumer>
+                implements DoubleConsumer {
+            final double[] array;
+
+            OfDouble(int size) {
+                this.array = new double[size];
+            }
+
+            @Override
+            public void accept(double t) {
+                array[index++] = t;
+            }
+
+            @Override
+            void forEach(DoubleConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+    }
+}
+
diff --git a/android-35/java/util/stream/StreamSupport.java b/android-35/java/util/stream/StreamSupport.java
new file mode 100644
index 0000000..9a1820c
--- /dev/null
+++ b/android-35/java/util/stream/StreamSupport.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Supplier;
+
+/**
+ * Low-level utility methods for creating and manipulating streams.
+ *
+ * <p>This class is mostly for library writers presenting stream views
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
+ *
+ * @since 1.8
+ */
+public final class StreamSupport {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private StreamSupport() {}
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Spliterator}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #stream(java.util.function.Supplier, int, boolean)} should be used
+     * to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param spliterator a {@code Spliterator} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     */
+    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
+        Objects.requireNonNull(spliterator);
+        return new ReferencePipeline.Head<>(spliterator,
+                                            StreamOpFlag.fromCharacteristics(spliterator),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Supplier} of {@code Spliterator}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #stream(java.util.Spliterator, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param supplier a {@code Supplier} of a {@code Spliterator}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     * @see #stream(java.util.Spliterator, boolean)
+     */
+    public static <T> Stream<T> stream(Supplier<? extends Spliterator<T>> supplier,
+                                       int characteristics,
+                                       boolean parallel) {
+        Objects.requireNonNull(supplier);
+        return new ReferencePipeline.Head<>(supplier,
+                                            StreamOpFlag.fromCharacteristics(characteristics),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #intStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfInt} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     */
+    public static IntStream intStream(Spliterator.OfInt spliterator, boolean parallel) {
+        return new IntPipeline.Head<>(spliterator,
+                                      StreamOpFlag.fromCharacteristics(spliterator),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Supplier} of {@code Spliterator.OfInt}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfInt}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfInt}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     * @see #intStream(java.util.Spliterator.OfInt, boolean)
+     */
+    public static IntStream intStream(Supplier<? extends Spliterator.OfInt> supplier,
+                                      int characteristics,
+                                      boolean parallel) {
+        return new IntPipeline.Head<>(supplier,
+                                      StreamOpFlag.fromCharacteristics(characteristics),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #longStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfLong} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     */
+    public static LongStream longStream(Spliterator.OfLong spliterator,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(spliterator,
+                                       StreamOpFlag.fromCharacteristics(spliterator),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Supplier} of {@code Spliterator.OfLong}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfLong}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfLong}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     * @see #longStream(java.util.Spliterator.OfLong, boolean)
+     */
+    public static LongStream longStream(Supplier<? extends Spliterator.OfLong> supplier,
+                                        int characteristics,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(supplier,
+                                       StreamOpFlag.fromCharacteristics(characteristics),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #doubleStream(java.util.function.Supplier, int, boolean)} should
+     * be used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator A {@code Spliterator.OfDouble} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     */
+    public static DoubleStream doubleStream(Spliterator.OfDouble spliterator,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(spliterator,
+                                         StreamOpFlag.fromCharacteristics(spliterator),
+                                         parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Supplier} of {@code Spliterator.OfDouble}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier A {@code Supplier} of a {@code Spliterator.OfDouble}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfDouble}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     * @see #doubleStream(java.util.Spliterator.OfDouble, boolean)
+     */
+    public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> supplier,
+                                            int characteristics,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(supplier,
+                                         StreamOpFlag.fromCharacteristics(characteristics),
+                                         parallel);
+    }
+}
diff --git a/android-35/java/util/stream/Streams.java b/android-35/java/util/stream/Streams.java
new file mode 100644
index 0000000..aa696c5
--- /dev/null
+++ b/android-35/java/util/stream/Streams.java
@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+/**
+ * Utility methods for operating on and creating streams.
+ *
+ * <p>Unless otherwise stated, streams are created as sequential streams.  A
+ * sequential stream can be transformed into a parallel stream by calling the
+ * {@code parallel()} method on the created stream.
+ *
+ * @since 1.8
+ */
+final class Streams {
+
+    private Streams() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * An {@code int} range spliterator.
+     */
+    static final class RangeIntSpliterator implements Spliterator.OfInt {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Integer.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private int from;
+        private final int upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeIntSpliterator(int from, int upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeIntSpliterator(int from, int upTo, int last) {
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final int i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        @IntrinsicCandidate
+        public void forEachRemaining(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            int i = from;
+            final int hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            // Ensure ranges of size > Integer.MAX_VALUE report the correct size
+            return ((long) upTo) - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as IntStream.range(0, Integer.MAX_VALUE)
+         * that is likely to be augmented with a limit operation that limits the
+         * number of elements to a count lower than this threshold.
+         */
+        private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private int splitPoint(long size) {
+            int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // Cast to int is safe since:
+            //   2 <= size < 2^32
+            //   2 <= d <= 8
+            return (int) (size / d);
+        }
+    }
+
+    /**
+     * A {@code long} range spliterator.
+     *
+     * This implementation cannot be used for ranges whose size is greater
+     * than Long.MAX_VALUE
+     */
+    static final class RangeLongSpliterator implements Spliterator.OfLong {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Long.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private long from;
+        private final long upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeLongSpliterator(long from, long upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeLongSpliterator(long from, long upTo, int last) {
+            assert upTo - from + last > 0;
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final long i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            long i = from;
+            final long hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            return upTo - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as LongStream.range(0, Long.MAX_VALUE)
+         * that is likely to be augmented with a limit operation that limits the
+         * number of elements to a count lower than this threshold.
+         */
+        private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private long splitPoint(long size) {
+            long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // 2 <= size <= Long.MAX_VALUE
+            return size / d;
+        }
+    }
+
+    private abstract static class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
+        // >= 0 when building, < 0 when built
+        // -1 == no elements
+        // -2 == one element, held by first
+        // -3 == two or more elements, held by buffer
+        int count;
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public S trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return -count - 1;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.ORDERED | Spliterator.IMMUTABLE;
+        }
+    }
+
+    static final class StreamBuilderImpl<T>
+            extends AbstractStreamBuilderImpl<T, Spliterator<T>>
+            implements Stream.Builder<T> {
+        // The first element in the stream
+        // valid if count == 1
+        T first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer<T> buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        StreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        StreamBuilderImpl(T t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(T t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer<>();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        public Stream.Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        @Override
+        public Stream<T> build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class IntStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
+            implements IntStream.Builder, Spliterator.OfInt {
+        // The first element in the stream
+        // valid if count == 1
+        int first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfInt buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        IntStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        IntStreamBuilderImpl(int t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(int t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfInt();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public IntStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class LongStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
+            implements LongStream.Builder, Spliterator.OfLong {
+        // The first element in the stream
+        // valid if count == 1
+        long first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfLong buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        LongStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        LongStreamBuilderImpl(long t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(long t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfLong();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public LongStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class DoubleStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
+            implements DoubleStream.Builder, Spliterator.OfDouble {
+        // The first element in the stream
+        // valid if count == 1
+        double first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfDouble buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        DoubleStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        DoubleStreamBuilderImpl(double t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(double t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfDouble();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public DoubleStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    abstract static class ConcatSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        protected final T_SPLITR aSpliterator;
+        protected final T_SPLITR bSpliterator;
+        // True when no split has occurred, otherwise false
+        boolean beforeSplit;
+        // Never read after splitting
+        final boolean unsized;
+
+        public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+            this.aSpliterator = aSpliterator;
+            this.bSpliterator = bSpliterator;
+            beforeSplit = true;
+            // The spliterator is known to be unsized before splitting if the
+            // sum of the estimates overflows.
+            unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
+        }
+
+        @Override
+        public T_SPLITR trySplit() {
+            @SuppressWarnings("unchecked")
+            T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit();
+            beforeSplit = false;
+            return ret;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            boolean hasNext;
+            if (beforeSplit) {
+                hasNext = aSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    beforeSplit = false;
+                    hasNext = bSpliterator.tryAdvance(consumer);
+                }
+            }
+            else
+                hasNext = bSpliterator.tryAdvance(consumer);
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            if (beforeSplit)
+                aSpliterator.forEachRemaining(consumer);
+            bSpliterator.forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            if (beforeSplit) {
+                // If one or both estimates are Long.MAX_VALUE then the sum
+                // will either be Long.MAX_VALUE or overflow to a negative value
+                long size = aSpliterator.estimateSize() + bSpliterator.estimateSize();
+                return (size >= 0) ? size : Long.MAX_VALUE;
+            }
+            else {
+                return bSpliterator.estimateSize();
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            if (beforeSplit) {
+                // Concatenation loses DISTINCT and SORTED characteristics
+                return aSpliterator.characteristics() & bSpliterator.characteristics()
+                       & ~(Spliterator.DISTINCT | Spliterator.SORTED
+                           | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0));
+            }
+            else {
+                return bSpliterator.characteristics();
+            }
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (beforeSplit)
+                throw new IllegalStateException();
+            return bSpliterator.getComparator();
+        }
+
+        static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
+            OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        private abstract static class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends ConcatSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                boolean hasNext;
+                if (beforeSplit) {
+                    hasNext = aSpliterator.tryAdvance(action);
+                    if (!hasNext) {
+                        beforeSplit = false;
+                        hasNext = bSpliterator.tryAdvance(action);
+                    }
+                }
+                else
+                    hasNext = bSpliterator.tryAdvance(action);
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                if (beforeSplit)
+                    aSpliterator.forEachRemaining(action);
+                bSpliterator.forEachRemaining(action);
+            }
+        }
+
+        static class OfInt
+                extends ConcatSpliterator.OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfLong
+                extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfDouble
+                extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+    }
+
+    /**
+     * Given two Runnables, return a Runnable that executes both in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composeWithExceptions(Runnable a, Runnable b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.run();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.run();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.run();
+            }
+        };
+    }
+
+    /**
+     * Given two streams, return a Runnable that
+     * executes both of their {@link BaseStream#close} methods in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.close();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.close();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.close();
+            }
+        };
+    }
+}
diff --git a/android-35/java/util/stream/TerminalOp.java b/android-35/java/util/stream/TerminalOp.java
new file mode 100644
index 0000000..a6e8ae1
--- /dev/null
+++ b/android-35/java/util/stream/TerminalOp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+
+/**
+ * An operation in a stream pipeline that takes a stream as input and produces
+ * a result or side-effect.  A {@code TerminalOp} has an input type and stream
+ * shape, and a result type.  A {@code TerminalOp} also has a set of
+ * <em>operation flags</em> that describes how the operation processes elements
+ * of the stream (such as short-circuiting or respecting encounter order; see
+ * {@link StreamOpFlag}).
+ *
+ * <p>A {@code TerminalOp} must provide a sequential and parallel implementation
+ * of the operation relative to a given stream source and set of intermediate
+ * operations.
+ *
+ * @param <E_IN> the type of input elements
+ * @param <R>    the type of the result
+ * @since 1.8
+ */
+interface TerminalOp<E_IN, R> {
+    /**
+     * Gets the shape of the input type of this operation.
+     *
+     * @implSpec The default returns {@code StreamShape.REFERENCE}.
+     *
+     * @return StreamShape of the input type of this operation
+     */
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    /**
+     * Gets the stream flags of the operation.  Terminal operations may set a
+     * limited subset of the stream flags defined in {@link StreamOpFlag}, and
+     * these flags are combined with the previously combined stream and
+     * intermediate operation flags for the pipeline.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the stream flags for this operation
+     * @see StreamOpFlag
+     */
+    default int getOpFlags() { return 0; }
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @implSpec The default performs a sequential evaluation of the operation
+     * using the specified {@code PipelineHelper}.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    default <P_IN> R evaluateParallel(PipelineHelper<E_IN> helper,
+                                      Spliterator<P_IN> spliterator) {
+        if (Tripwire.ENABLED)
+            Tripwire.trip(getClass(), "{0} triggering TerminalOp.evaluateParallel serial default");
+        return evaluateSequential(helper, spliterator);
+    }
+
+    /**
+     * Performs a sequential evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    <P_IN> R evaluateSequential(PipelineHelper<E_IN> helper,
+                                Spliterator<P_IN> spliterator);
+}
diff --git a/android-35/java/util/stream/TerminalSink.java b/android-35/java/util/stream/TerminalSink.java
new file mode 100644
index 0000000..9808d54
--- /dev/null
+++ b/android-35/java/util/stream/TerminalSink.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.function.Supplier;
+
+/**
+ * A {@link Sink} which accumulates state as elements are accepted, and allows
+ * a result to be retrieved after the computation is finished.
+ *
+ * @param <T> the type of elements to be accepted
+ * @param <R> the type of the result
+ *
+ * @since 1.8
+ */
+interface TerminalSink<T, R> extends Sink<T>, Supplier<R> { }
diff --git a/android-35/java/util/stream/Tripwire.java b/android-35/java/util/stream/Tripwire.java
new file mode 100644
index 0000000..962c7d3
--- /dev/null
+++ b/android-35/java/util/stream/Tripwire.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util.stream} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    @SuppressWarnings("removal")
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/android-35/java/util/stream/WhileOps.java b/android-35/java/util/stream/WhileOps.java
new file mode 100644
index 0000000..87fa83e
--- /dev/null
+++ b/android-35/java/util/stream/WhileOps.java
@@ -0,0 +1,1418 @@
+/*
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoublePredicate;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.LongConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+
+/**
+ * Factory for instances of a takeWhile and dropWhile operations
+ * that produce subsequences of their input stream.
+ *
+ * @since 9
+ */
+final class WhileOps {
+
+    static final int TAKE_FLAGS = StreamOpFlag.NOT_SIZED | StreamOpFlag.IS_SHORT_CIRCUIT;
+
+    static final int DROP_FLAGS = StreamOpFlag.NOT_SIZED;
+
+    /**
+     * Appends a "takeWhile" operation to the provided Stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt taking.
+     */
+    static <T> Stream<T> makeTakeWhileRef(AbstractPipeline<?, T, ?> upstream,
+                                          Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE, TAKE_FLAGS) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+                                                         Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Nodes.castingArray())
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfRef.Taking<>(
+                            helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                return new TakeWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                return new Sink.ChainedReference<T, T>(sink) {
+                    boolean take = true;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(T t) {
+                        if (take && (take = predicate.test(t))) {
+                            downstream.accept(t);
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return !take || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "takeWhile" operation to the provided IntStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt taking.
+     */
+    static IntStream makeTakeWhileInt(AbstractPipeline<?, Integer, ?> upstream,
+                                      IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE, TAKE_FLAGS) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Integer[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfInt.Taking(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Integer[]> generator) {
+                return new TakeWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    boolean take = true;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (take && (take = predicate.test(t))) {
+                            downstream.accept(t);
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return !take || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "takeWhile" operation to the provided LongStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt taking.
+     */
+    static LongStream makeTakeWhileLong(AbstractPipeline<?, Long, ?> upstream,
+                                        LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE, TAKE_FLAGS) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Long[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfLong.Taking(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<Long[]> generator) {
+                return new TakeWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    boolean take = true;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (take && (take = predicate.test(t))) {
+                            downstream.accept(t);
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return !take || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "takeWhile" operation to the provided DoubleStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt taking.
+     */
+    static DoubleStream makeTakeWhileDouble(AbstractPipeline<?, Double, ?> upstream,
+                                            DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE, TAKE_FLAGS) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Double[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfDouble.Taking(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                   Spliterator<P_IN> spliterator,
+                                                   IntFunction<Double[]> generator) {
+                return new TakeWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    boolean take = true;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (take && (take = predicate.test(t))) {
+                            downstream.accept(t);
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return !take || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * A specialization for the dropWhile operation that controls if
+     * elements to be dropped are counted and passed downstream.
+     * <p>
+     * This specialization is utilized by the {@link TakeWhileTask} for
+     * pipelines that are ordered.  In such cases elements cannot be dropped
+     * until all elements have been collected.
+     *
+     * @param <T> the type of both input and output elements
+     */
+    interface DropWhileOp<T> {
+        /**
+         * Accepts a {@code Sink} which will receive the results of this
+         * dropWhile operation, and return a {@code DropWhileSink} which
+         * accepts
+         * elements and which performs the dropWhile operation passing the
+         * results to the provided {@code Sink}.
+         *
+         * @param sink sink to which elements should be sent after processing
+         * @param retainAndCountDroppedElements true if elements to be dropped
+         * are counted and passed to the sink, otherwise such elements
+         * are actually dropped and not passed to the sink.
+         * @return a dropWhile sink
+         */
+        DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements);
+    }
+
+    /**
+     * A specialization for a dropWhile sink.
+     *
+     * @param <T> the type of both input and output elements
+     */
+    interface DropWhileSink<T> extends Sink<T> {
+        /**
+         * @return the could of elements that would have been dropped and
+         * instead were passed downstream.
+         */
+        long getDropCount();
+    }
+
+    /**
+     * Appends a "dropWhile" operation to the provided Stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt dropping.
+     */
+    static <T> Stream<T> makeDropWhileRef(AbstractPipeline<?, T, ?> upstream,
+                                          Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+
+        class Op extends ReferencePipeline.StatefulOp<T, T> implements DropWhileOp<T> {
+            public Op(AbstractPipeline<?, T, ?> upstream, StreamShape inputShape, int opFlags) {
+                super(upstream, inputShape, opFlags);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+                                                         Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Nodes.castingArray())
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfRef.Dropping<>(
+                            helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                return new DropWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                return opWrapSink(sink, false);
+            }
+
+            public DropWhileSink<T> opWrapSink(Sink<T> sink, boolean retainAndCountDroppedElements) {
+                class OpSink extends Sink.ChainedReference<T, T> implements DropWhileSink<T> {
+                    long dropCount;
+                    boolean take;
+
+                    OpSink() {
+                        super(sink);
+                    }
+
+                    @Override
+                    public void accept(T t) {
+                        boolean takeElement = take || (take = !predicate.test(t));
+
+                        // If ordered and element is dropped increment index
+                        // for possible future truncation
+                        if (retainAndCountDroppedElements && !takeElement)
+                            dropCount++;
+
+                        // If ordered need to process element, otherwise
+                        // skip if element is dropped
+                        if (retainAndCountDroppedElements || takeElement)
+                            downstream.accept(t);
+                    }
+
+                    @Override
+                    public long getDropCount() {
+                        return dropCount;
+                    }
+                }
+                return new OpSink();
+            }
+        }
+        return new Op(upstream, StreamShape.REFERENCE, DROP_FLAGS);
+    }
+
+    /**
+     * Appends a "dropWhile" operation to the provided IntStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt dropping.
+     */
+    static IntStream makeDropWhileInt(AbstractPipeline<?, Integer, ?> upstream,
+                                      IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        class Op extends IntPipeline.StatefulOp<Integer> implements DropWhileOp<Integer> {
+            public Op(AbstractPipeline<?, Integer, ?> upstream, StreamShape inputShape, int opFlags) {
+                super(upstream, inputShape, opFlags);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Integer[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfInt.Dropping(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Integer[]> generator) {
+                return new DropWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return opWrapSink(sink, false);
+            }
+
+            public DropWhileSink<Integer> opWrapSink(Sink<Integer> sink, boolean retainAndCountDroppedElements) {
+                class OpSink extends Sink.ChainedInt<Integer> implements DropWhileSink<Integer> {
+                    long dropCount;
+                    boolean take;
+
+                    OpSink() {
+                        super(sink);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        boolean takeElement = take || (take = !predicate.test(t));
+
+                        // If ordered and element is dropped increment index
+                        // for possible future truncation
+                        if (retainAndCountDroppedElements && !takeElement)
+                            dropCount++;
+
+                        // If ordered need to process element, otherwise
+                        // skip if element is dropped
+                        if (retainAndCountDroppedElements || takeElement)
+                            downstream.accept(t);
+                    }
+
+                    @Override
+                    public long getDropCount() {
+                        return dropCount;
+                    }
+                }
+                return new OpSink();
+            }
+        }
+        return new Op(upstream, StreamShape.INT_VALUE, DROP_FLAGS);
+    }
+
+    /**
+     * Appends a "dropWhile" operation to the provided LongStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt dropping.
+     */
+    static LongStream makeDropWhileLong(AbstractPipeline<?, Long, ?> upstream,
+                                        LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        class Op extends LongPipeline.StatefulOp<Long> implements DropWhileOp<Long> {
+            public Op(AbstractPipeline<?, Long, ?> upstream, StreamShape inputShape, int opFlags) {
+                super(upstream, inputShape, opFlags);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Long[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfLong.Dropping(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<Long[]> generator) {
+                return new DropWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return opWrapSink(sink, false);
+            }
+
+            public DropWhileSink<Long> opWrapSink(Sink<Long> sink, boolean retainAndCountDroppedElements) {
+                class OpSink extends Sink.ChainedLong<Long> implements DropWhileSink<Long> {
+                    long dropCount;
+                    boolean take;
+
+                    OpSink() {
+                        super(sink);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        boolean takeElement = take || (take = !predicate.test(t));
+
+                        // If ordered and element is dropped increment index
+                        // for possible future truncation
+                        if (retainAndCountDroppedElements && !takeElement)
+                            dropCount++;
+
+                        // If ordered need to process element, otherwise
+                        // skip if element is dropped
+                        if (retainAndCountDroppedElements || takeElement)
+                            downstream.accept(t);
+                    }
+
+                    @Override
+                    public long getDropCount() {
+                        return dropCount;
+                    }
+                }
+                return new OpSink();
+            }
+        }
+        return new Op(upstream, StreamShape.LONG_VALUE, DROP_FLAGS);
+    }
+
+    /**
+     * Appends a "dropWhile" operation to the provided DoubleStream.
+     *
+     * @param upstream a reference stream with element type T
+     * @param predicate the predicate that returns false to halt dropping.
+     */
+    static DoubleStream makeDropWhileDouble(AbstractPipeline<?, Double, ?> upstream,
+                                            DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        class Op extends DoublePipeline.StatefulOp<Double> implements DropWhileOp<Double> {
+            public Op(AbstractPipeline<?, Double, ?> upstream, StreamShape inputShape, int opFlags) {
+                super(upstream, inputShape, opFlags);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return opEvaluateParallel(helper, spliterator, Double[]::new)
+                            .spliterator();
+                }
+                else {
+                    return new UnorderedWhileSpliterator.OfDouble.Dropping(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator), false, predicate);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                   Spliterator<P_IN> spliterator,
+                                                   IntFunction<Double[]> generator) {
+                return new DropWhileTask<>(this, helper, spliterator, generator)
+                        .invoke();
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return opWrapSink(sink, false);
+            }
+
+            public DropWhileSink<Double> opWrapSink(Sink<Double> sink, boolean retainAndCountDroppedElements) {
+                class OpSink extends Sink.ChainedDouble<Double> implements DropWhileSink<Double> {
+                    long dropCount;
+                    boolean take;
+
+                    OpSink() {
+                        super(sink);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        boolean takeElement = take || (take = !predicate.test(t));
+
+                        // If ordered and element is dropped increment index
+                        // for possible future truncation
+                        if (retainAndCountDroppedElements && !takeElement)
+                            dropCount++;
+
+                        // If ordered need to process element, otherwise
+                        // skip if element is dropped
+                        if (retainAndCountDroppedElements || takeElement)
+                            downstream.accept(t);
+                    }
+
+                    @Override
+                    public long getDropCount() {
+                        return dropCount;
+                    }
+                }
+                return new OpSink();
+            }
+        }
+        return new Op(upstream, StreamShape.DOUBLE_VALUE, DROP_FLAGS);
+    }
+
+    //
+
+    /**
+     * A spliterator supporting takeWhile and dropWhile operations over an
+     * underlying spliterator whose covered elements have no encounter order.
+     * <p>
+     * Concrete subclasses of this spliterator support reference and primitive
+     * types for takeWhile and dropWhile.
+     * <p>
+     * For the takeWhile operation if during traversal taking completes then
+     * taking is cancelled globally for the splitting and traversal of all
+     * related spliterators.
+     * Cancellation is governed by a shared {@link AtomicBoolean} instance.  A
+     * spliterator in the process of taking when cancellation occurs will also
+     * be cancelled but not necessarily immediately.  To reduce contention on
+     * the {@link AtomicBoolean} instance, cancellation make be acted on after
+     * a small number of additional elements have been traversed.
+     * <p>
+     * For the dropWhile operation if during traversal dropping completes for
+     * some, but not all elements, then it is cancelled globally for the
+     * traversal of all related spliterators (splitting is not cancelled).
+     * Cancellation is governed in the same manner as for the takeWhile
+     * operation.
+     *
+     * @param <T> the type of elements returned by this spliterator
+     * @param <T_SPLITR> the type of the spliterator
+     */
+    abstract static class UnorderedWhileSpliterator<T, T_SPLITR extends Spliterator<T>> implements Spliterator<T> {
+        // Power of two constant minus one used for modulus of count
+        static final int CANCEL_CHECK_COUNT = (1 << 6) - 1;
+
+        // The underlying spliterator
+        final T_SPLITR s;
+        // True if no splitting should be performed, if true then
+        // this spliterator may be used for an underlying spliterator whose
+        // covered elements have an encounter order
+        // See use in stream take/dropWhile default methods
+        final boolean noSplitting;
+        // True when operations are cancelled for all related spliterators
+        // For taking, spliterators cannot split or traversed
+        // For dropping, spliterators cannot be traversed
+        final AtomicBoolean cancel;
+        // True while taking or dropping should be performed when traversing
+        boolean takeOrDrop = true;
+        // The count of elements traversed
+        int count;
+
+        UnorderedWhileSpliterator(T_SPLITR s, boolean noSplitting) {
+            this.s = s;
+            this.noSplitting = noSplitting;
+            this.cancel = new AtomicBoolean();
+        }
+
+        UnorderedWhileSpliterator(T_SPLITR s, UnorderedWhileSpliterator<T, T_SPLITR> parent) {
+            this.s = s;
+            this.noSplitting = parent.noSplitting;
+            this.cancel = parent.cancel;
+        }
+
+        @Override
+        public long estimateSize() {
+            return s.estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            // Size is not known
+            return s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public long getExactSizeIfKnown() {
+            return -1L;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return s.getComparator();
+        }
+
+        @Override
+        public T_SPLITR trySplit() {
+            @SuppressWarnings("unchecked")
+            T_SPLITR ls = noSplitting ? null : (T_SPLITR) s.trySplit();
+            return ls != null ? makeSpliterator(ls) : null;
+        }
+
+        boolean checkCancelOnCount() {
+            return count != 0 || !cancel.get();
+        }
+
+        abstract T_SPLITR makeSpliterator(T_SPLITR s);
+
+        abstract static class OfRef<T> extends UnorderedWhileSpliterator<T, Spliterator<T>> implements Consumer<T> {
+            final Predicate<? super T> p;
+            T t;
+
+            OfRef(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
+                super(s, noSplitting);
+                this.p = p;
+            }
+
+            OfRef(Spliterator<T> s, OfRef<T> parent) {
+                super(s, parent);
+                this.p = parent.p;
+            }
+
+            @Override
+            public void accept(T t) {
+                count = (count + 1) & CANCEL_CHECK_COUNT;
+                this.t = t;
+            }
+
+            static final class Taking<T> extends OfRef<T> {
+                Taking(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
+                    super(s, noSplitting, p);
+                }
+
+                Taking(Spliterator<T> s, Taking<T> parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(Consumer<? super T> action) {
+                    boolean test = true;
+                    if (takeOrDrop &&               // If can take
+                        checkCancelOnCount() && // and if not cancelled
+                        s.tryAdvance(this) &&   // and if advanced one element
+                        (test = p.test(t))) {   // and test on element passes
+                        action.accept(t);           // then accept element
+                        return true;
+                    }
+                    else {
+                        // Taking is finished
+                        takeOrDrop = false;
+                        // Cancel all further traversal and splitting operations
+                        // only if test of element failed (short-circuited)
+                        if (!test)
+                            cancel.set(true);
+                        return false;
+                    }
+                }
+
+                @Override
+                public Spliterator<T> trySplit() {
+                    // Do not split if all operations are cancelled
+                    return cancel.get() ? null : super.trySplit();
+                }
+
+                @Override
+                Spliterator<T> makeSpliterator(Spliterator<T> s) {
+                    return new Taking<>(s, this);
+                }
+            }
+
+            static final class Dropping<T> extends OfRef<T> {
+                Dropping(Spliterator<T> s, boolean noSplitting, Predicate<? super T> p) {
+                    super(s, noSplitting, p);
+                }
+
+                Dropping(Spliterator<T> s, Dropping<T> parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(Consumer<? super T> action) {
+                    if (takeOrDrop) {
+                        takeOrDrop = false;
+                        boolean adv;
+                        boolean dropped = false;
+                        while ((adv = s.tryAdvance(this)) &&  // If advanced one element
+                               checkCancelOnCount() &&        // and if not cancelled
+                               p.test(t)) {                   // and test on element passes
+                            dropped = true;                   // then drop element
+                        }
+
+                        // Report advanced element, if any
+                        if (adv) {
+                            // Cancel all further dropping if one or more elements
+                            // were previously dropped
+                            if (dropped)
+                                cancel.set(true);
+                            action.accept(t);
+                        }
+                        return adv;
+                    }
+                    else {
+                        return s.tryAdvance(action);
+                    }
+                }
+
+                @Override
+                Spliterator<T> makeSpliterator(Spliterator<T> s) {
+                    return new Dropping<>(s, this);
+                }
+            }
+        }
+
+        abstract static class OfInt extends UnorderedWhileSpliterator<Integer, Spliterator.OfInt> implements IntConsumer, Spliterator.OfInt {
+            final IntPredicate p;
+            int t;
+
+            OfInt(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
+                super(s, noSplitting);
+                this.p = p;
+            }
+
+            OfInt(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
+                super(s, parent);
+                this.p = parent.p;
+            }
+
+            @Override
+            public void accept(int t) {
+                count = (count + 1) & CANCEL_CHECK_COUNT;
+                this.t = t;
+            }
+
+            static final class Taking extends UnorderedWhileSpliterator.OfInt {
+                Taking(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Taking(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(IntConsumer action) {
+                    boolean test = true;
+                    if (takeOrDrop &&               // If can take
+                        checkCancelOnCount() && // and if not cancelled
+                        s.tryAdvance(this) &&   // and if advanced one element
+                        (test = p.test(t))) {   // and test on element passes
+                        action.accept(t);           // then accept element
+                        return true;
+                    }
+                    else {
+                        // Taking is finished
+                        takeOrDrop = false;
+                        // Cancel all further traversal and splitting operations
+                        // only if test of element failed (short-circuited)
+                        if (!test)
+                            cancel.set(true);
+                        return false;
+                    }
+                }
+
+                @Override
+                public Spliterator.OfInt trySplit() {
+                    // Do not split if all operations are cancelled
+                    return cancel.get() ? null : super.trySplit();
+                }
+
+                @Override
+                Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
+                    return new Taking(s, this);
+                }
+            }
+
+            static final class Dropping extends UnorderedWhileSpliterator.OfInt {
+                Dropping(Spliterator.OfInt s, boolean noSplitting, IntPredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Dropping(Spliterator.OfInt s, UnorderedWhileSpliterator.OfInt parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(IntConsumer action) {
+                    if (takeOrDrop) {
+                        takeOrDrop = false;
+                        boolean adv;
+                        boolean dropped = false;
+                        while ((adv = s.tryAdvance(this)) &&  // If advanced one element
+                               checkCancelOnCount() &&        // and if not cancelled
+                               p.test(t)) {                   // and test on element passes
+                            dropped = true;                   // then drop element
+                        }
+
+                        // Report advanced element, if any
+                        if (adv) {
+                            // Cancel all further dropping if one or more elements
+                            // were previously dropped
+                            if (dropped)
+                                cancel.set(true);
+                            action.accept(t);
+                        }
+                        return adv;
+                    }
+                    else {
+                        return s.tryAdvance(action);
+                    }
+                }
+
+                @Override
+                Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
+                    return new Dropping(s, this);
+                }
+            }
+        }
+
+        abstract static class OfLong extends UnorderedWhileSpliterator<Long, Spliterator.OfLong> implements LongConsumer, Spliterator.OfLong {
+            final LongPredicate p;
+            long t;
+
+            OfLong(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
+                super(s, noSplitting);
+                this.p = p;
+            }
+
+            OfLong(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
+                super(s, parent);
+                this.p = parent.p;
+            }
+
+            @Override
+            public void accept(long t) {
+                count = (count + 1) & CANCEL_CHECK_COUNT;
+                this.t = t;
+            }
+
+            static final class Taking extends UnorderedWhileSpliterator.OfLong {
+                Taking(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Taking(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(LongConsumer action) {
+                    boolean test = true;
+                    if (takeOrDrop &&               // If can take
+                        checkCancelOnCount() && // and if not cancelled
+                        s.tryAdvance(this) &&   // and if advanced one element
+                        (test = p.test(t))) {   // and test on element passes
+                        action.accept(t);           // then accept element
+                        return true;
+                    }
+                    else {
+                        // Taking is finished
+                        takeOrDrop = false;
+                        // Cancel all further traversal and splitting operations
+                        // only if test of element failed (short-circuited)
+                        if (!test)
+                            cancel.set(true);
+                        return false;
+                    }
+                }
+
+                @Override
+                public Spliterator.OfLong trySplit() {
+                    // Do not split if all operations are cancelled
+                    return cancel.get() ? null : super.trySplit();
+                }
+
+                @Override
+                Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
+                    return new Taking(s, this);
+                }
+            }
+
+            static final class Dropping extends UnorderedWhileSpliterator.OfLong {
+                Dropping(Spliterator.OfLong s, boolean noSplitting, LongPredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Dropping(Spliterator.OfLong s, UnorderedWhileSpliterator.OfLong parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(LongConsumer action) {
+                    if (takeOrDrop) {
+                        takeOrDrop = false;
+                        boolean adv;
+                        boolean dropped = false;
+                        while ((adv = s.tryAdvance(this)) &&  // If advanced one element
+                               checkCancelOnCount() &&        // and if not cancelled
+                               p.test(t)) {                   // and test on element passes
+                            dropped = true;                   // then drop element
+                        }
+
+                        // Report advanced element, if any
+                        if (adv) {
+                            // Cancel all further dropping if one or more elements
+                            // were previously dropped
+                            if (dropped)
+                                cancel.set(true);
+                            action.accept(t);
+                        }
+                        return adv;
+                    }
+                    else {
+                        return s.tryAdvance(action);
+                    }
+                }
+
+                @Override
+                Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
+                    return new Dropping(s, this);
+                }
+            }
+        }
+
+        abstract static class OfDouble extends UnorderedWhileSpliterator<Double, Spliterator.OfDouble> implements DoubleConsumer, Spliterator.OfDouble {
+            final DoublePredicate p;
+            double t;
+
+            OfDouble(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
+                super(s, noSplitting);
+                this.p = p;
+            }
+
+            OfDouble(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
+                super(s, parent);
+                this.p = parent.p;
+            }
+
+            @Override
+            public void accept(double t) {
+                count = (count + 1) & CANCEL_CHECK_COUNT;
+                this.t = t;
+            }
+
+            static final class Taking extends UnorderedWhileSpliterator.OfDouble {
+                Taking(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Taking(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(DoubleConsumer action) {
+                    boolean test = true;
+                    if (takeOrDrop &&               // If can take
+                        checkCancelOnCount() && // and if not cancelled
+                        s.tryAdvance(this) &&   // and if advanced one element
+                        (test = p.test(t))) {   // and test on element passes
+                        action.accept(t);           // then accept element
+                        return true;
+                    }
+                    else {
+                        // Taking is finished
+                        takeOrDrop = false;
+                        // Cancel all further traversal and splitting operations
+                        // only if test of element failed (short-circuited)
+                        if (!test)
+                            cancel.set(true);
+                        return false;
+                    }
+                }
+
+                @Override
+                public Spliterator.OfDouble trySplit() {
+                    // Do not split if all operations are cancelled
+                    return cancel.get() ? null : super.trySplit();
+                }
+
+                @Override
+                Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
+                    return new Taking(s, this);
+                }
+            }
+
+            static final class Dropping extends UnorderedWhileSpliterator.OfDouble {
+                Dropping(Spliterator.OfDouble s, boolean noSplitting, DoublePredicate p) {
+                    super(s, noSplitting, p);
+                }
+
+                Dropping(Spliterator.OfDouble s, UnorderedWhileSpliterator.OfDouble parent) {
+                    super(s, parent);
+                }
+
+                @Override
+                public boolean tryAdvance(DoubleConsumer action) {
+                    if (takeOrDrop) {
+                        takeOrDrop = false;
+                        boolean adv;
+                        boolean dropped = false;
+                        while ((adv = s.tryAdvance(this)) &&  // If advanced one element
+                               checkCancelOnCount() &&        // and if not cancelled
+                               p.test(t)) {                   // and test on element passes
+                            dropped = true;                   // then drop element
+                        }
+
+                        // Report advanced element, if any
+                        if (adv) {
+                            // Cancel all further dropping if one or more elements
+                            // were previously dropped
+                            if (dropped)
+                                cancel.set(true);
+                            action.accept(t);
+                        }
+                        return adv;
+                    }
+                    else {
+                        return s.tryAdvance(action);
+                    }
+                }
+
+                @Override
+                Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
+                    return new Dropping(s, this);
+                }
+            }
+        }
+    }
+
+
+    //
+
+    /**
+     * {@code ForkJoinTask} implementing takeWhile computation.
+     * <p>
+     * If the pipeline has encounter order then all tasks to the right of
+     * a task where traversal was short-circuited are cancelled.
+     * The results of completed (and cancelled) tasks are discarded.
+     * The result of merging a short-circuited left task and right task (which
+     * may or may not be short-circuited) is that left task.
+     * <p>
+     * If the pipeline has no encounter order then all tasks to the right of
+     * a task where traversal was short-circuited are cancelled.
+     * The results of completed (and possibly cancelled) tasks are not
+     * discarded, as there is no need to throw away computed results.
+     * The result of merging does not change if a left task was
+     * short-circuited.
+     * No attempt is made, once a leaf task stopped taking, for it to cancel
+     * all other tasks, and further more, short-circuit the computation with its
+     * result.
+     *
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class TakeWhileTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, TakeWhileTask<P_IN, P_OUT>> {
+        private final AbstractPipeline<P_OUT, P_OUT, ?> op;
+        private final IntFunction<P_OUT[]> generator;
+        private final boolean isOrdered;
+        private long thisNodeSize;
+        // True if a short-circuited
+        private boolean shortCircuited;
+        // True if completed, must be set after the local result
+        private volatile boolean completed;
+
+        TakeWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
+                      PipelineHelper<P_OUT> helper,
+                      Spliterator<P_IN> spliterator,
+                      IntFunction<P_OUT[]> generator) {
+            super(helper, spliterator);
+            this.op = op;
+            this.generator = generator;
+            this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
+        }
+
+        TakeWhileTask(TakeWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+            this.generator = parent.generator;
+            this.isOrdered = parent.isOrdered;
+        }
+
+        @Override
+        protected TakeWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new TakeWhileTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<P_OUT> getEmptyResult() {
+            return Nodes.emptyNode(op.getOutputShape());
+        }
+
+        @Override
+        protected final Node<P_OUT> doLeaf() {
+            Node.Builder<P_OUT> builder = helper.makeNodeBuilder(-1, generator);
+            Sink<P_OUT> s = op.opWrapSink(helper.getStreamAndOpFlags(), builder);
+
+            if (shortCircuited = helper.copyIntoWithCancel(helper.wrapSink(s), spliterator)) {
+                // Cancel later nodes if the predicate returned false
+                // during traversal
+                cancelLaterNodes();
+            }
+
+            Node<P_OUT> node = builder.build();
+            thisNodeSize = node.count();
+            return node;
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                Node<P_OUT> result;
+                shortCircuited = leftChild.shortCircuited | rightChild.shortCircuited;
+                if (isOrdered && canceled) {
+                    thisNodeSize = 0;
+                    result = getEmptyResult();
+                }
+                else if (isOrdered && leftChild.shortCircuited) {
+                    // If taking finished on the left node then
+                    // use the left node result
+                    thisNodeSize = leftChild.thisNodeSize;
+                    result = leftChild.getLocalResult();
+                }
+                else {
+                    thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
+                    result = merge();
+                }
+
+                setLocalResult(result);
+            }
+
+            completed = true;
+            super.onCompletion(caller);
+        }
+
+        Node<P_OUT> merge() {
+            if (leftChild.thisNodeSize == 0) {
+                // If the left node size is 0 then
+                // use the right node result
+                return rightChild.getLocalResult();
+            }
+            else if (rightChild.thisNodeSize == 0) {
+                // If the right node size is 0 then
+                // use the left node result
+                return leftChild.getLocalResult();
+            }
+            else {
+                // Combine the left and right nodes
+                return Nodes.conc(op.getOutputShape(),
+                                  leftChild.getLocalResult(), rightChild.getLocalResult());
+            }
+        }
+
+        @Override
+        protected void cancel() {
+            super.cancel();
+            if (isOrdered && completed)
+                // If the task is completed then clear the result, if any
+                // to aid GC
+                setLocalResult(getEmptyResult());
+        }
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing dropWhile computation.
+     * <p>
+     * If the pipeline has encounter order then each leaf task will not
+     * drop elements but will obtain a count of the elements that would have
+     * been otherwise dropped. That count is used as an index to track
+     * elements to be dropped. Merging will update the index so it corresponds
+     * to the index that is the end of the global prefix of elements to be
+     * dropped. The root is truncated according to that index.
+     * <p>
+     * If the pipeline has no encounter order then each leaf task will drop
+     * elements. Leaf tasks are ordinarily merged. No truncation of the root
+     * node is required.
+     * No attempt is made, once a leaf task stopped dropping, for it to cancel
+     * all other tasks, and further more, short-circuit the computation with
+     * its result.
+     *
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class DropWhileTask<P_IN, P_OUT>
+            extends AbstractTask<P_IN, P_OUT, Node<P_OUT>, DropWhileTask<P_IN, P_OUT>> {
+        private final AbstractPipeline<P_OUT, P_OUT, ?> op;
+        private final IntFunction<P_OUT[]> generator;
+        private final boolean isOrdered;
+        private long thisNodeSize;
+        // The index from which elements of the node should be taken
+        // i.e. the node should be truncated from [takeIndex, thisNodeSize)
+        // Equivalent to the count of dropped elements
+        private long index;
+
+        DropWhileTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
+                      PipelineHelper<P_OUT> helper,
+                      Spliterator<P_IN> spliterator,
+                      IntFunction<P_OUT[]> generator) {
+            super(helper, spliterator);
+            assert op instanceof DropWhileOp;
+            this.op = op;
+            this.generator = generator;
+            this.isOrdered = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
+        }
+
+        DropWhileTask(DropWhileTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+            this.generator = parent.generator;
+            this.isOrdered = parent.isOrdered;
+        }
+
+        @Override
+        protected DropWhileTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new DropWhileTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<P_OUT> doLeaf() {
+            boolean isChild = !isRoot();
+            // If this not the root and pipeline is ordered and size is known
+            // then pre-size the builder
+            long sizeIfKnown = isChild && isOrdered && StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
+                               ? op.exactOutputSizeIfKnown(spliterator)
+                               : -1;
+            Node.Builder<P_OUT> builder = helper.makeNodeBuilder(sizeIfKnown, generator);
+            @SuppressWarnings("unchecked")
+            DropWhileOp<P_OUT> dropOp = (DropWhileOp<P_OUT>) op;
+            // If this leaf is the root then there is no merging on completion
+            // and there is no need to retain dropped elements
+            DropWhileSink<P_OUT> s = dropOp.opWrapSink(builder, isOrdered && isChild);
+            helper.wrapAndCopyInto(s, spliterator);
+
+            Node<P_OUT> node = builder.build();
+            thisNodeSize = node.count();
+            index = s.getDropCount();
+            return node;
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                if (isOrdered) {
+                    index = leftChild.index;
+                    // If a contiguous sequence of dropped elements
+                    // include those of the right node, if any
+                    if (index == leftChild.thisNodeSize)
+                        index += rightChild.index;
+                }
+
+                thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
+                Node<P_OUT> result = merge();
+                setLocalResult(isRoot() ? doTruncate(result) : result);
+            }
+
+            super.onCompletion(caller);
+        }
+
+        private Node<P_OUT> merge() {
+            if (leftChild.thisNodeSize == 0) {
+                // If the left node size is 0 then
+                // use the right node result
+                return rightChild.getLocalResult();
+            }
+            else if (rightChild.thisNodeSize == 0) {
+                // If the right node size is 0 then
+                // use the left node result
+                return leftChild.getLocalResult();
+            }
+            else {
+                // Combine the left and right nodes
+                return Nodes.conc(op.getOutputShape(),
+                                  leftChild.getLocalResult(), rightChild.getLocalResult());
+            }
+        }
+
+        private Node<P_OUT> doTruncate(Node<P_OUT> input) {
+            return isOrdered
+                   ? input.truncate(index, input.count(), generator)
+                   : input;
+        }
+    }
+}
diff --git a/android-35/java/util/stream/package-info.java b/android-35/java/util/stream/package-info.java
new file mode 100644
index 0000000..635f44e
--- /dev/null
+++ b/android-35/java/util/stream/package-info.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Classes to support functional-style operations on streams of elements, such
+ * as map-reduce transformations on collections.  For example:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(b -> b.getColor() == RED)
+ *                      .mapToInt(b -> b.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce on the stream
+ * to obtain the sum of the weights of the red widgets.  (Summation is an
+ * example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation.)
+ *
+ * <p>The key abstraction introduced in this package is <em>stream</em>.  The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long}, and
+ * {@code double} types.  Streams differ from collections in several ways:
+ *
+ * <ul>
+ *     <li>No storage.  A stream is not a data structure that stores elements;
+ *     instead, it conveys elements from a source such as a data structure,
+ *     an array, a generator function, or an I/O channel, through a pipeline of
+ *     computational operations.</li>
+ *     <li>Functional in nature.  An operation on a stream produces a result,
+ *     but does not modify its source.  For example, filtering a {@code Stream}
+ *     obtained from a collection produces a new {@code Stream} without the
+ *     filtered elements, rather than removing elements from the source
+ *     collection.</li>
+ *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping,
+ *     or duplicate removal, can be implemented lazily, exposing opportunities
+ *     for optimization.  For example, "find the first {@code String} with
+ *     three consecutive vowels" need not examine all the input strings.
+ *     Stream operations are divided into intermediate ({@code Stream}-producing)
+ *     operations and terminal (value- or side-effect-producing) operations.
+ *     Intermediate operations are always lazy.</li>
+ *     <li>Possibly unbounded.  While collections have a finite size, streams
+ *     need not.  Short-circuiting operations such as {@code limit(n)} or
+ *     {@code findFirst()} can allow computations on infinite streams to
+ *     complete in finite time.</li>
+ *     <li>Consumable. The elements of a stream are only visited once during
+ *     the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ *     must be generated to revisit the same elements of the source.
+ *     </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ *     <li>From a {@link java.util.Collection} via the {@code stream()} and
+ *     {@code parallelStream()} methods;</li>
+ *     <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ *     <li>From static factory methods on the stream classes, such as
+ *     {@link java.util.stream.Stream#of(Object[])},
+ *     {@link java.util.stream.IntStream#range(int, int)}
+ *     or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};</li>
+ *     <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ *     <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ *     <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ *     <li>Numerous other stream-bearing methods in the JDK, including
+ *     {@link java.util.BitSet#stream()},
+ *     {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ *     and {@link java.util.jar.JarFile#stream()}.</li>
+ * </ul>
+ *
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a id="StreamOps">Stream operations and pipelines</a></h2>
+ *
+ * <p>Stream operations are divided into <em>intermediate</em> and
+ * <em>terminal</em> operations, and are combined to form <em>stream
+ * pipelines</em>.  A stream pipeline consists of a source (such as a
+ * {@code Collection}, an array, a generator function, or an I/O channel);
+ * followed by zero or more intermediate operations such as
+ * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
+ * as {@code Stream.forEach} or {@code Stream.reduce}.
+ *
+ * <p>Intermediate operations return a new stream.  They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code filter()} does not actually perform any filtering, but instead
+ * creates a new stream that, when traversed, contains the elements of
+ * the initial stream that match the given predicate.  Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
+ *
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream.  In almost all cases, terminal operations are <em>eager</em>,
+ * completing their traversal of the data source and processing of the pipeline
+ * before returning.  Only the terminal operations {@code iterator()} and
+ * {@code spliterator()} are not; these are provided as an "escape hatch" to enable
+ * arbitrary client-controlled pipeline traversals in the event that the
+ * existing operations are not sufficient to the task.
+ *
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
+ *
+ * <p>Intermediate operations are further divided into <em>stateless</em>
+ * and <em>stateful</em> operations. Stateless operations, such as {@code filter}
+ * and {@code map}, retain no state from previously seen element when processing
+ * a new element -- each element can be processed
+ * independently of operations on other elements.  Stateful operations, such as
+ * {@code distinct} and {@code sorted}, may incorporate state from previously
+ * seen elements when processing new elements.
+ *
+ * <p>Stateful operations may need to process the entire input
+ * before producing a result.  For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream.  As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations may require multiple passes on the data or may need to buffer
+ * significant data.  Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
+ *
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result.  A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time.  Having a short-circuiting operation in the pipeline
+ * is a necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.
+ *
+ * <h3><a id="Parallelism">Parallelism</a></h3>
+ *
+ * <p>Processing elements with an explicit {@code for-}loop is inherently serial.
+ * Streams facilitate parallel execution by reframing the computation as a pipeline of
+ * aggregate operations, rather than as imperative operations on each individual
+ * element.  All streams operations can execute either in serial or in parallel.
+ * The stream implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested.  For example, {@code Collection} has methods
+ * {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these streams can be efficiently parallelized by
+ * invoking their {@link java.util.stream.BaseStream#parallel()} method.
+ * To execute the prior "sum of weights of widgets" query in parallel, we would
+ * do:
+ *
+ * <pre>{@code
+ *     int sumOfWeights = widgets.parallelStream()
+ *                               .filter(b -> b.getColor() == RED)
+ *                               .mapToInt(b -> b.getWeight())
+ *                               .sum();
+ * }</pre>
+ *
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, using "{@code parallelStream()}"
+ * instead of "{@code stream()}". The stream pipeline is executed sequentially or
+ * in parallel depending on the mode of the stream on which the terminal operation
+ * is invoked. The sequential or parallel mode of a stream can be determined with the
+ * {@link java.util.stream.BaseStream#isParallel()} method, and the
+ * stream's mode can be modified with the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations.
+ * The most recent sequential or parallel mode setting applies to the
+ * execution of the entire stream pipeline.
+ *
+ * <p>Except for operations identified as explicitly nondeterministic, such
+ * as {@code findAny()}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions.  To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
+ *
+ * <h3><a id="NonInterference">Non-interference</a></h3>
+ *
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline.  Except for the escape-hatch operations {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes.  For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The notable exception to this are streams whose sources are concurrent
+ * collections, which are specifically designed to handle concurrent modification.
+ * Concurrent stream sources are those whose {@code Spliterator} reports the
+ * {@code CONCURRENT} characteristic.
+ *
+ * <p>Accordingly, behavioral parameters in stream pipelines whose source might
+ * not be concurrent should never modify the stream's data source.
+ * A behavioral parameter is said to <em>interfere</em> with a non-concurrent
+ * data source if it modifies, or causes to be
+ * modified, the stream's data source.  The need for non-interference applies
+ * to all pipelines, not just parallel ones.  Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant behavior.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements.  For example, consider the following code:
+ *
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     l.add("three");
+ *     String s = sl.collect(joining(" "));
+ * }</pre>
+ *
+ * First a list is created consisting of two strings: "one" and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK collections, and most other JDK classes,
+ * are well-behaved in this manner; for streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * <h3><a id="Statelessness">Stateless behaviors</a></h3>
+ *
+ * Stream pipeline results may be nondeterministic or incorrect if the behavioral
+ * parameters to the stream operations are <em>stateful</em>.  A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline.  An example of a stateful lambda is the parameter
+ * to {@code map()} in:
+ *
+ * <pre>{@code
+ *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
+ *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
+ * }</pre>
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * <p>Note also that attempting to access mutable state from behavioral parameters
+ * presents you with a bad choice with respect to safety and performance; if
+ * you do not synchronize access to that state, you have a data race and
+ * therefore your code is broken, but if you do synchronize access to that
+ * state, you risk having contention undermine the parallelism you are seeking
+ * to benefit from.  The best approach is to avoid stateful behavioral
+ * parameters to stream operations entirely; there is usually a way to
+ * restructure the stream pipeline to avoid statefulness.
+ *
+ * <h3><a id="SideEffects">Side-effects</a></h3>
+ *
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards.
+ *
+ * <p>If the behavioral parameters do have side-effects, unless explicitly
+ * stated, there are no guarantees as to:
+ * <ul>
+ *    <li>the <a href="../concurrent/package-summary.html#MemoryVisibility">
+ *    <i>visibility</i></a> of those side-effects to other threads;</li>
+ *    <li>that different operations on the "same" element within the same stream
+ *    pipeline are executed in the same thread; and</li>
+ *    <li>that behavioral parameters are always invoked, since a stream
+ *    implementation is free to elide operations (or entire stages) from a
+ *    stream pipeline if it can prove that it would not affect the result of the
+ *    computation.
+ *    </li>
+ * </ul>
+ * <p>The ordering of side-effects may be surprising.  Even when a pipeline is
+ * constrained to produce a <em>result</em> that is consistent with the
+ * encounter order of the stream source (for example,
+ * {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()}
+ * must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order
+ * in which the mapper function is applied to individual elements, or in what
+ * thread any behavioral parameter is executed for a given element.
+ *
+ * <p>The eliding of side-effects may also be surprising.  With the exception of
+ * terminal operations {@link java.util.stream.Stream#forEach forEach} and
+ * {@link java.util.stream.Stream#forEachOrdered forEachOrdered}, side-effects
+ * of behavioral parameters may not always be executed when the stream
+ * implementation can optimize away the execution of behavioral parameters
+ * without affecting the result of the computation.  (For a specific example
+ * see the API note documented on the {@link java.util.stream.Stream#count count}
+ * operation.)
+ *
+ * <p>Many computations where one might be tempted to use side-effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. However, side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless.  A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ *     ArrayList<String> results = new ArrayList<>();
+ *     stream.filter(s -> pattern.matcher(s).matches())
+ *           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
+ * }</pre>
+ *
+ * This code unnecessarily uses side-effects.  If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism.  Furthermore, using side-effects here is completely
+ * unnecessary; the {@code forEach()} can simply be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization:
+ *
+ * <pre>{@code
+ *     List<String> results =
+ *         stream.filter(s -> pattern.matcher(s).matches())
+ *               .toList();  // No side-effects!
+ * }</pre>
+ *
+ * <h3><a id="Ordering">Ordering</a></h3>
+ *
+ * <p>Streams may or may not have a defined <em>encounter order</em>.  Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations.  Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not.  Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
+ *
+ * <p>If a stream is ordered, most operations are constrained to operate on the
+ * elements in their encounter order; if the source of a stream is a {@code List}
+ * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
+ * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
+ * order, then any permutation of the values {@code [2, 4, 6]} would be a valid
+ * result.
+ *
+ * <p>For sequential streams, the presence or absence of an encounter order does
+ * not affect performance, only determinism.  If a stream is ordered, repeated
+ * execution of identical stream pipelines on an identical source will produce
+ * an identical result; if it is not ordered, repeated execution might produce
+ * different results.
+ *
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient execution.  Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements
+ * is not relevant.  Similarly, operations that are intrinsically tied to encounter order,
+ * such as {@code limit()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream has an encounter order, but the user does not
+ * particularly <em>care</em> about that encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may
+ * improve parallel performance for some stateful or terminal operations.
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, still parallelize efficiently even under ordering constraints.
+ *
+ * <h2><a id="Reduction">Reduction operations</a></h2>
+ *
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating elements into a list.  The streams classes have
+ * multiple forms of general reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * as well as multiple specialized reduction forms such as
+ * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()},
+ * or {@link java.util.stream.IntStream#count() count()}.
+ *
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
+ * <pre>{@code
+ *    int sum = 0;
+ *    for (int x : numbers) {
+ *       sum += x;
+ *    }
+ * }</pre>
+ * However, there are good reasons to prefer a reduce operation
+ * over a mutative accumulation such as the above.  Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * are <a href="package-summary.html#Associativity">associative</a> and
+ * <a href="package-summary.html#Statelessness">stateless</a>.
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
+ * }</pre>
+ * or:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
+ * <pre>{@code
+ *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>Reduction parallellizes well because the implementation
+ * can operate on subsets of the data in parallel, and then combine the
+ * intermediate results to get the final correct answer.  (Even if the language
+ * had a "parallel for-each" construct, the mutative accumulation approach would
+ * still require the developer to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would then likely eliminate any performance gain from
+ * parallelism.)  Using {@code reduce()} instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization
+ * required.
+ *
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for-loops with bulk operations.  If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
+ * <pre>{@code
+ *     OptionalInt heaviest = widgets.parallelStream()
+ *                                   .mapToInt(Widget::getWeight)
+ *                                   .max();
+ * }</pre>
+ *
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
+ * <pre>{@code
+ * <U> U reduce(U identity,
+ *              BiFunction<U, ? super T, U> accumulator,
+ *              BinaryOperator<U> combiner);
+ * }</pre>
+ * Here, the <em>identity</em> element is both an initial seed value for the reduction
+ * and a default result if there are no input elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produces a new
+ * partial result. The <em>combiner</em> function combines two partial results
+ * to produce a new partial result.  (The combiner is necessary in parallel
+ * reductions, where the input is partitioned, a partial accumulation computed
+ * for each partition, and then the partial results are combined to produce a
+ * final result.)
+ *
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function: for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
+ *
+ * <p>The three-argument form is a generalization of the two-argument form,
+ * incorporating a mapping step into the accumulation step.  We could
+ * re-cast the simple sum-of-weights example using the more general form as
+ * follows:
+ * <pre>{@code
+ *     int sumOfWeights = widgets.stream()
+ *                               .reduce(0,
+ *                                       (sum, b) -> sum + b.getWeight(),
+ *                                       Integer::sum);
+ * }</pre>
+ * though the explicit map-reduce form is more readable and therefore should
+ * usually be preferred. The generalized form is provided for cases where
+ * significant work can be optimized away by combining mapping and reducing
+ * into a single function.
+ *
+ * <h3><a id="MutableReduction">Mutable reduction</a></h3>
+ *
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
+ * as it processes the elements in the stream.
+ *
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
+ * <pre>{@code
+ *     String concatenated = strings.reduce("", String::concat)
+ * }</pre>
+ *
+ * <p>We would get the desired result, and it would even work in parallel.  However,
+ * we might not be happy about the performance!  Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters.  A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings.  We can use the same technique to
+ * parallelize mutable reduction as we do with ordinary reduction.
+ *
+ * <p>The mutable reduction operation is called
+ * {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as a {@code Collection}.
+ * A {@code collect} operation requires three functions:
+ * a supplier function to construct new instances of the result container, an
+ * accumulator function to incorporate an input element into a result
+ * container, and a combining function to merge the contents of one result
+ * container into another.  The form of this is very similar to the general
+ * form of ordinary reduction:
+ * <pre>{@code
+ * <R> R collect(Supplier<R> supplier,
+ *               BiConsumer<R, ? super T> accumulator,
+ *               BiConsumer<R, R> combiner);
+ * }</pre>
+ * <p>As with {@code reduce()}, a benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
+ * <pre>{@code
+ *     ArrayList<String> strings = new ArrayList<>();
+ *     for (T element : stream) {
+ *         strings.add(element.toString());
+ *     }
+ * }</pre>
+ * Or we could use a parallelizable collect form:
+ * <pre>{@code
+ *     ArrayList<String> strings = stream.collect(() -> new ArrayList<>(),
+ *                                                (c, e) -> c.add(e.toString()),
+ *                                                (c1, c2) -> c1.addAll(c2));
+ * }</pre>
+ * or, pulling the mapping operation out of the accumulator function, we could
+ * express it more succinctly as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+ * }</pre>
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
+ *
+ * <p>The three aspects of {@code collect} -- supplier, accumulator, and
+ * combiner -- are tightly coupled.  We can use the abstraction of a
+ * {@link java.util.stream.Collector} to capture all three aspects.  The
+ * above example for collecting strings into a {@code List} can be rewritten
+ * using a standard {@code Collector} as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(Collectors.toList());
+ * }</pre>
+ *
+ * <p>Packaging mutable reductions into a Collector has another advantage:
+ * composability.  The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including combinators
+ * that transform one collector into another.  For example, suppose we have a
+ * collector that computes the sum of the salaries of a stream of
+ * employees, as follows:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary);
+ * }</pre>
+ *
+ * (The {@code ?} for the second type parameter merely indicates that we don't
+ * care about the intermediate representation used by this collector.)
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector) groupingBy}:
+ *
+ * <pre>{@code
+ *     Map<Department, Integer> salariesByDept
+ *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                            summingSalaries));
+ * }</pre>
+ *
+ * <p>As with the regular reduction operation, {@code collect()} operations can
+ * only be parallelized if appropriate conditions are met.  For any partially
+ * accumulated result, combining it with an empty result container must
+ * produce an equivalent result.  That is, for a partially accumulated result
+ * {@code p} that is the result of any series of accumulator and combiner
+ * invocations, {@code p} must be equivalent to
+ * {@code combiner.apply(p, supplier.get())}.
+ *
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result.  For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * }</pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <h3><a id="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3>
+ *
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .collect(Collectors.groupingBy(Transaction::getBuyer));
+ * }</pre>
+ * it may actually be counterproductive to perform the operation in parallel.
+ * This is because the combining step (merging one {@code Map} into another by
+ * key) can be expensive for some {@code Map} implementations.
+ *
+ * <p>Suppose, however, that the result container used in this reduction
+ * was a concurrently modifiable collection -- such as a
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a
+ * <em>concurrent</em> reduction.
+ *
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic.  However, a concurrent collection also has a downside.  If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
+ * implementation will only perform a concurrent reduction if
+ * <ul>
+ * <li>The stream is parallel;</li>
+ * <li>The collector has the
+ * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic,
+ * and;</li>
+ * <li>Either the stream is unordered, or the collector has the
+ * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
+ * </ul>
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method.  For example:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .unordered()
+ *               .collect(groupingByConcurrent(Transaction::getBuyer));
+ * }</pre>
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
+ *
+ * <p>Note that if it is important that the elements for a given key appear in
+ * the order they appear in the source, then we cannot use a concurrent
+ * reduction, as ordering is one of the casualties of concurrent insertion.
+ * We would then be constrained to implement either a sequential reduction or
+ * a merge-based parallel reduction.
+ *
+ * <h3><a id="Associativity">Associativity</a></h3>
+ *
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
+ * <pre>{@code
+ *     (a op b) op c == a op (b op c)
+ * }</pre>
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
+ * <pre>{@code
+ *     a op b op c op d == (a op b) op (c op d)
+ * }</pre>
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
+ *
+ * <p>Examples of associative operations include numeric addition, min, and
+ * max, and string concatenation.
+ *
+ * <h2><a id="StreamSources">Low-level stream construction</a></h2>
+ *
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream.  How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of
+ * low-level methods for creating a stream, all using some form of a
+ * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
+ * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
+ * elements, with support for sequentially advancing, bulk traversal, and
+ * splitting off some portion of the input into another spliterator which can
+ * be processed in parallel.  At the lowest level, all streams are driven by a
+ * spliterator.
+ *
+ * <p>There are a number of implementation choices in implementing a
+ * spliterator, nearly all of which are tradeoffs between simplicity of
+ * implementation and runtime performance of streams using that spliterator.
+ * The simplest, but least performant, way to create a spliterator is to
+ * create one from an iterator using
+ * {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the
+ * underlying data set), as well as being constrained to a simplistic
+ * splitting algorithm.
+ *
+ * <p>A higher-quality spliterator will provide balanced and known-size
+ * splits, accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
+ *
+ * <p>Spliterators for mutable data sources have an additional challenge;
+ * timing of binding to the data, since the data could change between the time
+ * the spliterator is created and the time the stream pipeline is executed.
+ * Ideally, a spliterator for a stream would report a characteristic of
+ * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
+ * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
+ * cannot directly supply a recommended spliterator, it may indirectly supply
+ * a spliterator using a {@code Supplier}, and construct a stream via the
+ * {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
+ * operation of the stream pipeline commences.
+ *
+ * <p>These requirements significantly reduce the scope of potential
+ * interference between mutations of the stream source and execution of stream
+ * pipelines. Streams based on spliterators with the desired characteristics,
+ * or those using the Supplier-based factory forms, are immune to
+ * modifications of the data source prior to commencement of the terminal
+ * operation (provided the behavioral parameters to the stream operations meet
+ * the required criteria for non-interference and statelessness).  See
+ * <a href="package-summary.html#NonInterference">Non-Interference</a>
+ * for more details.
+ *
+ * @since 1.8
+ */
+package java.util.stream;
+
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
diff --git a/android-35/java/util/zip/Adler32.java b/android-35/java/util/zip/Adler32.java
new file mode 100644
index 0000000..04e57d4
--- /dev/null
+++ b/android-35/java/util/zip/Adler32.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import sun.nio.ch.DirectBuffer;
+
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+/**
+ * A class that can be used to compute the Adler-32 checksum of a data
+ * stream. An Adler-32 checksum is almost as reliable as a CRC-32 but
+ * can be computed much faster.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.</p>
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class Adler32 implements Checksum {
+
+    private int adler = 1;
+
+    /**
+     * Creates a new Adler32 object.
+     */
+    public Adler32() {
+    }
+
+    /**
+     * Updates the checksum with the specified byte (the low eight
+     * bits of the argument b).
+     */
+    @Override
+    public void update(int b) {
+        adler = update(adler, b);
+    }
+
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code off} is negative, or {@code len} is negative, or
+     *         {@code off+len} is negative or greater than the length of
+     *         the array {@code b}.
+     */
+    @Override
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        adler = updateBytes(adler, b, off, len);
+    }
+
+    // Android-changed: method kept during jdk17u update for compatibility.
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @param b the byte array to update the checksum with
+     */
+    @Override
+    public void update(byte[] b) {
+        adler = updateBytes(adler, b, 0, b.length);
+    }
+
+    /**
+     * Updates the checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated with the remaining bytes in the buffer, starting
+     * at the buffer's position. Upon return, the buffer's position will be
+     * updated to its limit; its limit will not have been changed.
+     *
+     * @since 1.8
+     */
+    @Override
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer.isDirect()) {
+            try {
+                adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem);
+            } finally {
+                Reference.reachabilityFence(buffer);
+            }
+        } else if (buffer.hasArray()) {
+            adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
+            while (buffer.hasRemaining()) {
+                int length = Math.min(buffer.remaining(), b.length);
+                buffer.get(b, 0, length);
+                update(b, 0, length);
+            }
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets the checksum to initial value.
+     */
+    @Override
+    public void reset() {
+        adler = 1;
+    }
+
+    /**
+     * Returns the checksum value.
+     */
+    @Override
+    public long getValue() {
+        return (long)adler & 0xffffffffL;
+    }
+
+    private static native int update(int adler, int b);
+
+    @IntrinsicCandidate
+    private static native int updateBytes(int adler, byte[] b, int off,
+                                          int len);
+    @IntrinsicCandidate
+    private static native int updateByteBuffer(int adler, long addr,
+                                               int off, int len);
+}
diff --git a/android-35/java/util/zip/CRC32.java b/android-35/java/util/zip/CRC32.java
new file mode 100644
index 0000000..49c9c95
--- /dev/null
+++ b/android-35/java/util/zip/CRC32.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import sun.nio.ch.DirectBuffer;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+/**
+ * A class that can be used to compute the CRC-32 of a data stream.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.</p>
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class CRC32 implements Checksum {
+    private int crc;
+
+    /**
+     * Creates a new CRC32 object.
+     */
+    public CRC32() {
+    }
+
+
+    /**
+     * Updates the CRC-32 checksum with the specified byte (the low
+     * eight bits of the argument b).
+     */
+    @Override
+    public void update(int b) {
+        crc = update(crc, b);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code off} is negative, or {@code len} is negative, or
+     *         {@code off+len} is negative or greater than the length of
+     *         the array {@code b}.
+     */
+    @Override
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        crc = updateBytes(crc, b, off, len);
+    }
+
+    // Android-changed: method kept during jdk17u update for compatibility.
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @param b the array of bytes to update the checksum with
+     */
+    @Override
+    public void update(byte[] b) {
+        crc = updateBytes(crc, b, 0, b.length);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated with the remaining bytes in the buffer, starting
+     * at the buffer's position. Upon return, the buffer's position will be
+     * updated to its limit; its limit will not have been changed.
+     *
+     * @since 1.8
+     */
+    @Override
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer.isDirect()) {
+            try {
+                crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem);
+            } finally {
+                Reference.reachabilityFence(buffer);
+            }
+        } else if (buffer.hasArray()) {
+            crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
+            while (buffer.hasRemaining()) {
+                int length = Math.min(buffer.remaining(), b.length);
+                buffer.get(b, 0, length);
+                update(b, 0, length);
+            }
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets CRC-32 to initial value.
+     */
+    @Override
+    public void reset() {
+        crc = 0;
+    }
+
+    /**
+     * Returns CRC-32 value.
+     */
+    @Override
+    public long getValue() {
+        return (long)crc & 0xffffffffL;
+    }
+
+    @IntrinsicCandidate
+    private static native int update(int crc, int b);
+
+    private static int updateBytes(int crc, byte[] b, int off, int len) {
+        updateBytesCheck(b, off, len);
+        return updateBytes0(crc, b, off, len);
+    }
+
+    @IntrinsicCandidate
+    private static native int updateBytes0(int crc, byte[] b, int off, int len);
+
+    private static void updateBytesCheck(byte[] b, int off, int len) {
+        if (len <= 0) {
+            return;  // not an error because updateBytesImpl won't execute if len <= 0
+        }
+
+        Objects.requireNonNull(b);
+
+        if (off < 0 || off >= b.length) {
+            throw new ArrayIndexOutOfBoundsException(off);
+        }
+
+        int endIndex = off + len - 1;
+        if (endIndex < 0 || endIndex >= b.length) {
+            throw new ArrayIndexOutOfBoundsException(endIndex);
+        }
+    }
+
+    private static int updateByteBuffer(int alder, long addr,
+                                        int off, int len) {
+        updateByteBufferCheck(addr);
+        return updateByteBuffer0(alder, addr, off, len);
+    }
+
+    @IntrinsicCandidate
+    private static native int updateByteBuffer0(int alder, long addr,
+                                                int off, int len);
+
+    private static void updateByteBufferCheck(long addr) {
+        // Performs only a null check because bounds checks
+        // are not easy to do on raw addresses.
+        if (addr == 0L) {
+            throw new NullPointerException();
+        }
+    }
+}
diff --git a/android-35/java/util/zip/CRC32C.java b/android-35/java/util/zip/CRC32C.java
new file mode 100644
index 0000000..fa138d4
--- /dev/null
+++ b/android-35/java/util/zip/CRC32C.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.zip;
+
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import jdk.internal.misc.Unsafe;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * A class that can be used to compute the CRC-32C of a data stream.
+ *
+ * <p>
+ * CRC-32C is defined in <a href="http://www.ietf.org/rfc/rfc3720.txt">RFC
+ * 3720</a>: Internet Small Computer Systems Interface (iSCSI).
+ * </p>
+ *
+ * <p>
+ * Passing a {@code null} argument to a method in this class will cause a
+ * {@link NullPointerException} to be thrown.
+ * </p>
+ *
+ * @since 9
+ */
+public final class CRC32C implements Checksum {
+
+    /*
+     * This CRC-32C implementation uses the 'slicing-by-8' algorithm described
+     * in the paper "A Systematic Approach to Building High Performance
+     * Software-Based CRC Generators" by Michael E. Kounavis and Frank L. Berry,
+     * Intel Research and Development
+     */
+
+    /**
+     * CRC-32C Polynomial
+     */
+    private static final int CRC32C_POLY = 0x1EDC6F41;
+    private static final int REVERSED_CRC32C_POLY = Integer.reverse(CRC32C_POLY);
+
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    // Lookup tables
+    // Lookup table for single byte calculations
+    private static final int[] byteTable;
+    // Lookup tables for bulk operations in 'slicing-by-8' algorithm
+    private static final int[][] byteTables = new int[8][256];
+    private static final int[] byteTable0 = byteTables[0];
+    private static final int[] byteTable1 = byteTables[1];
+    private static final int[] byteTable2 = byteTables[2];
+    private static final int[] byteTable3 = byteTables[3];
+    private static final int[] byteTable4 = byteTables[4];
+    private static final int[] byteTable5 = byteTables[5];
+    private static final int[] byteTable6 = byteTables[6];
+    private static final int[] byteTable7 = byteTables[7];
+
+    static {
+        // Generate lookup tables
+        // High-order polynomial term stored in LSB of r.
+        for (int index = 0; index < byteTables[0].length; index++) {
+           int r = index;
+            for (int i = 0; i < Byte.SIZE; i++) {
+                if ((r & 1) != 0) {
+                    r = (r >>> 1) ^ REVERSED_CRC32C_POLY;
+                } else {
+                    r >>>= 1;
+                }
+            }
+            byteTables[0][index] = r;
+        }
+
+        for (int index = 0; index < byteTables[0].length; index++) {
+            int r = byteTables[0][index];
+
+            for (int k = 1; k < byteTables.length; k++) {
+                r = byteTables[0][r & 0xFF] ^ (r >>> 8);
+                byteTables[k][index] = r;
+            }
+        }
+
+        if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
+            byteTable = byteTables[0];
+        } else { // ByteOrder.BIG_ENDIAN
+            byteTable = new int[byteTable0.length];
+            System.arraycopy(byteTable0, 0, byteTable, 0, byteTable0.length);
+            for (int[] table : byteTables) {
+                for (int index = 0; index < table.length; index++) {
+                    table[index] = Integer.reverseBytes(table[index]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Calculated CRC-32C value
+     */
+    private int crc = 0xFFFFFFFF;
+
+    /**
+     * Creates a new CRC32C object.
+     */
+    public CRC32C() {
+    }
+
+    /**
+     * Updates the CRC-32C checksum with the specified byte (the low eight bits
+     * of the argument b).
+     */
+    @Override
+    public void update(int b) {
+        crc = (crc >>> 8) ^ byteTable[(crc ^ (b & 0xFF)) & 0xFF];
+    }
+
+    /**
+     * Updates the CRC-32C checksum with the specified array of bytes.
+     *
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code off} is negative, or {@code len} is negative, or
+     *         {@code off+len} is negative or greater than the length of
+     *         the array {@code b}.
+     */
+    @Override
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        crc = updateBytes(crc, b, off, (off + len));
+    }
+
+    /**
+     * Updates the CRC-32C checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated with the remaining bytes in the buffer, starting
+     * at the buffer's position. Upon return, the buffer's position will be
+     * updated to its limit; its limit will not have been changed.
+     */
+    @Override
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0) {
+            return;
+        }
+
+        if (buffer.isDirect()) {
+            try {
+                crc = updateDirectByteBuffer(crc, ((DirectBuffer) buffer).address(),
+                        pos, limit);
+            } finally {
+                Reference.reachabilityFence(buffer);
+            }
+        } else if (buffer.hasArray()) {
+            crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(),
+                              limit + buffer.arrayOffset());
+        } else {
+            byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
+            while (buffer.hasRemaining()) {
+                int length = Math.min(buffer.remaining(), b.length);
+                buffer.get(b, 0, length);
+                update(b, 0, length);
+            }
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets CRC-32C to initial value.
+     */
+    @Override
+    public void reset() {
+        crc = 0xFFFFFFFF;
+    }
+
+    /**
+     * Returns CRC-32C value.
+     */
+    @Override
+    public long getValue() {
+        return (~crc) & 0xFFFFFFFFL;
+    }
+
+    /**
+     * Updates the CRC-32C checksum with the specified array of bytes.
+     */
+    @IntrinsicCandidate
+    private static int updateBytes(int crc, byte[] b, int off, int end) {
+
+        // Do only byte reads for arrays so short they can't be aligned
+        // or if bytes are stored with a larger witdh than one byte.,%
+        if (end - off >= 8 && Unsafe.ARRAY_BYTE_INDEX_SCALE == 1) {
+
+            // align on 8 bytes
+            int alignLength
+                    = (8 - ((Unsafe.ARRAY_BYTE_BASE_OFFSET + off) & 0x7)) & 0x7;
+            for (int alignEnd = off + alignLength; off < alignEnd; off++) {
+                crc = (crc >>> 8) ^ byteTable[(crc ^ b[off]) & 0xFF];
+            }
+
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+                crc = Integer.reverseBytes(crc);
+            }
+
+            // slicing-by-8
+            for (; off < (end - Long.BYTES); off += Long.BYTES) {
+                int firstHalf;
+                int secondHalf;
+                if (Unsafe.ADDRESS_SIZE == 4) {
+                    // On 32 bit platforms read two ints instead of a single 64bit long
+                    firstHalf = UNSAFE.getInt(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off);
+                    secondHalf = UNSAFE.getInt(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off
+                                               + Integer.BYTES);
+                } else {
+                    long value = UNSAFE.getLong(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off);
+                    if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
+                        firstHalf = (int) value;
+                        secondHalf = (int) (value >>> 32);
+                    } else { // ByteOrder.BIG_ENDIAN
+                        firstHalf = (int) (value >>> 32);
+                        secondHalf = (int) value;
+                    }
+                }
+                crc ^= firstHalf;
+                if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
+                    crc = byteTable7[crc & 0xFF]
+                            ^ byteTable6[(crc >>> 8) & 0xFF]
+                            ^ byteTable5[(crc >>> 16) & 0xFF]
+                            ^ byteTable4[crc >>> 24]
+                            ^ byteTable3[secondHalf & 0xFF]
+                            ^ byteTable2[(secondHalf >>> 8) & 0xFF]
+                            ^ byteTable1[(secondHalf >>> 16) & 0xFF]
+                            ^ byteTable0[secondHalf >>> 24];
+                } else { // ByteOrder.BIG_ENDIAN
+                    crc = byteTable0[secondHalf & 0xFF]
+                            ^ byteTable1[(secondHalf >>> 8) & 0xFF]
+                            ^ byteTable2[(secondHalf >>> 16) & 0xFF]
+                            ^ byteTable3[secondHalf >>> 24]
+                            ^ byteTable4[crc & 0xFF]
+                            ^ byteTable5[(crc >>> 8) & 0xFF]
+                            ^ byteTable6[(crc >>> 16) & 0xFF]
+                            ^ byteTable7[crc >>> 24];
+                }
+            }
+
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+                crc = Integer.reverseBytes(crc);
+            }
+        }
+
+        // Tail
+        for (; off < end; off++) {
+            crc = (crc >>> 8) ^ byteTable[(crc ^ b[off]) & 0xFF];
+        }
+
+        return crc;
+    }
+
+    /**
+     * Updates the CRC-32C checksum reading from the specified address.
+     */
+    @IntrinsicCandidate
+    private static int updateDirectByteBuffer(int crc, long address,
+                                              int off, int end) {
+
+        // Do only byte reads for arrays so short they can't be aligned
+        if (end - off >= 8) {
+
+            // align on 8 bytes
+            int alignLength = (8 - (int) ((address + off) & 0x7)) & 0x7;
+            for (int alignEnd = off + alignLength; off < alignEnd; off++) {
+                crc = (crc >>> 8)
+                        ^ byteTable[(crc ^ UNSAFE.getByte(address + off)) & 0xFF];
+            }
+
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+                crc = Integer.reverseBytes(crc);
+            }
+
+            // slicing-by-8
+            for (; off <= (end - Long.BYTES); off += Long.BYTES) {
+                // Always reading two ints as reading a long followed by
+                // shifting and casting was slower.
+                int firstHalf = UNSAFE.getInt(address + off);
+                int secondHalf = UNSAFE.getInt(address + off + Integer.BYTES);
+                crc ^= firstHalf;
+                if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
+                    crc = byteTable7[crc & 0xFF]
+                            ^ byteTable6[(crc >>> 8) & 0xFF]
+                            ^ byteTable5[(crc >>> 16) & 0xFF]
+                            ^ byteTable4[crc >>> 24]
+                            ^ byteTable3[secondHalf & 0xFF]
+                            ^ byteTable2[(secondHalf >>> 8) & 0xFF]
+                            ^ byteTable1[(secondHalf >>> 16) & 0xFF]
+                            ^ byteTable0[secondHalf >>> 24];
+                } else { // ByteOrder.BIG_ENDIAN
+                    crc = byteTable0[secondHalf & 0xFF]
+                            ^ byteTable1[(secondHalf >>> 8) & 0xFF]
+                            ^ byteTable2[(secondHalf >>> 16) & 0xFF]
+                            ^ byteTable3[secondHalf >>> 24]
+                            ^ byteTable4[crc & 0xFF]
+                            ^ byteTable5[(crc >>> 8) & 0xFF]
+                            ^ byteTable6[(crc >>> 16) & 0xFF]
+                            ^ byteTable7[crc >>> 24];
+                }
+            }
+
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+                crc = Integer.reverseBytes(crc);
+            }
+        }
+
+        // Tail
+        for (; off < end; off++) {
+            crc = (crc >>> 8)
+                    ^ byteTable[(crc ^ UNSAFE.getByte(address + off)) & 0xFF];
+        }
+
+        return crc;
+    }
+}
diff --git a/android-35/java/util/zip/CheckedInputStream.java b/android-35/java/util/zip/CheckedInputStream.java
new file mode 100644
index 0000000..a97c589
--- /dev/null
+++ b/android-35/java/util/zip/CheckedInputStream.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * An input stream that also maintains a checksum of the data being read.
+ * The checksum can then be used to verify the integrity of the input data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class CheckedInputStream extends FilterInputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an input stream using the specified Checksum.
+     * @param in the input stream
+     * @param cksum the Checksum
+     */
+    public CheckedInputStream(InputStream in, Checksum cksum) {
+        super(in);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Reads a byte. Will block if no input is available.
+     * @return the byte read, or -1 if the end of the stream is reached.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        int b = in.read();
+        if (b != -1) {
+            cksum.update(b);
+        }
+        return b;
+    }
+
+    /**
+     * Reads into an array of bytes. If {@code len} is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and {@code 0} is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array {@code b}
+     * @param len the maximum number of bytes read
+     * @return    the actual number of bytes read, or -1 if the end
+     *            of the stream is reached.
+     * @throws     NullPointerException If {@code buf} is {@code null}.
+     * @throws     IndexOutOfBoundsException If {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code buf.length - off}
+     * @throws    IOException if an I/O error has occurred
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        len = in.read(buf, off, len);
+        if (len != -1) {
+            cksum.update(buf, off, len);
+        }
+        return len;
+    }
+
+    /**
+     * Skips specified number of bytes of input.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @throws    IOException if an I/O error has occurred
+     */
+    public long skip(long n) throws IOException {
+        byte[] buf = new byte[512];
+        long total = 0;
+        while (total < n) {
+            long len = n - total;
+            len = read(buf, 0, len < buf.length ? (int)len : buf.length);
+            if (len == -1) {
+                return total;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Returns the Checksum for this input stream.
+     * @return the Checksum value
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/android-35/java/util/zip/CheckedOutputStream.java b/android-35/java/util/zip/CheckedOutputStream.java
new file mode 100644
index 0000000..10a0b26
--- /dev/null
+++ b/android-35/java/util/zip/CheckedOutputStream.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * An output stream that also maintains a checksum of the data being
+ * written. The checksum can then be used to verify the integrity of
+ * the output data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class CheckedOutputStream extends FilterOutputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an output stream with the specified Checksum.
+     * @param out the output stream
+     * @param cksum the checksum
+     */
+    public CheckedOutputStream(OutputStream out, Checksum cksum) {
+        super(out);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Writes a byte. Will block until the byte is actually written.
+     * @param b the byte to be written
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        out.write(b);
+        cksum.update(b);
+    }
+
+    /**
+     * Writes an array of bytes. Will block until the bytes are
+     * actually written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the number of bytes to be written
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        out.write(b, off, len);
+        cksum.update(b, off, len);
+    }
+
+    /**
+     * Returns the Checksum for this output stream.
+     * @return the Checksum
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/android-35/java/util/zip/Checksum.java b/android-35/java/util/zip/Checksum.java
new file mode 100644
index 0000000..db9490c
--- /dev/null
+++ b/android-35/java/util/zip/Checksum.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An interface representing a data checksum.
+ *
+ * @author David Connelly
+ * @since 1.1
+ */
+public interface Checksum {
+
+    /**
+     * Updates the current checksum with the specified byte.
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b);
+
+    /**
+     * Updates the current checksum with the specified array of bytes.
+     *
+     * @implSpec This default implementation is equal to calling
+     * {@code update(b, 0, b.length)}.
+     *
+     * @param b the array of bytes to update the checksum with
+     *
+     * @throws NullPointerException
+     *         if {@code b} is {@code null}
+     *
+     * @since 9
+     */
+    default public void update(byte[] b) {
+        update(b, 0, b.length);
+    }
+
+    /**
+     * Updates the current checksum with the specified array of bytes.
+     *
+     * @param b the byte array to update the checksum with
+     * @param off the start offset of the data
+     * @param len the number of bytes to use for the update
+     */
+    public void update(byte[] b, int off, int len);
+
+    /**
+     * Updates the current checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated with the remaining bytes in the buffer, starting
+     * at the buffer's position. Upon return, the buffer's position will be
+     * updated to its limit; its limit will not have been changed.
+     *
+     * @apiNote For best performance with DirectByteBuffer and other ByteBuffer
+     * implementations without a backing array implementers of this interface
+     * should override this method.
+     *
+     * @implSpec The default implementation has the following behavior.<br>
+     * For ByteBuffers backed by an accessible byte array.
+     * <pre>{@code
+     * update(buffer.array(),
+     *        buffer.position() + buffer.arrayOffset(),
+     *        buffer.remaining());
+     * }</pre>
+     * For ByteBuffers not backed by an accessible byte array.
+     * <pre>{@code
+     * byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
+     * while (buffer.hasRemaining()) {
+     *     int length = Math.min(buffer.remaining(), b.length);
+     *     buffer.get(b, 0, length);
+     *     update(b, 0, length);
+     * }
+     * }</pre>
+     *
+     * @param buffer the ByteBuffer to update the checksum with
+     *
+     * @throws NullPointerException
+     *         if {@code buffer} is {@code null}
+     *
+     * @since 9
+     */
+    default public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0) {
+            return;
+        }
+        if (buffer.hasArray()) {
+            update(buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
+            while (buffer.hasRemaining()) {
+                int length = Math.min(buffer.remaining(), b.length);
+                buffer.get(b, 0, length);
+                update(b, 0, length);
+            }
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Returns the current checksum value.
+     *
+     * @return the current checksum value
+     */
+    public long getValue();
+
+    /**
+     * Resets the checksum to its initial value.
+     */
+    public void reset();
+}
diff --git a/android-35/java/util/zip/DataFormatException.java b/android-35/java/util/zip/DataFormatException.java
new file mode 100644
index 0000000..cfb6eb6
--- /dev/null
+++ b/android-35/java/util/zip/DataFormatException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that a data format error has occurred.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class DataFormatException extends Exception {
+    @java.io.Serial
+    private static final long serialVersionUID = 2219632870893641452L;
+
+    /**
+     * Constructs a DataFormatException with no detail message.
+     */
+    public DataFormatException() {
+        super();
+    }
+
+    /**
+     * Constructs a DataFormatException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the String containing a detail message
+     */
+    public DataFormatException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/zip/Deflater.java b/android-35/java/util/zip/Deflater.java
new file mode 100644
index 0000000..9910016
--- /dev/null
+++ b/android-35/java/util/zip/Deflater.java
@@ -0,0 +1,982 @@
+/*
+ * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
+import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * This class provides support for general purpose compression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package-description">java.util.zip
+ * package description</a>.
+ * <p>
+ * This class deflates sequences of bytes into ZLIB compressed data format.
+ * The input byte sequence is provided in either byte array or byte buffer,
+ * via one of the {@code setInput()} methods. The output byte sequence is
+ * written to the output byte array or byte buffer passed to the
+ * {@code deflate()} methods.
+ * <p>
+ * The following code fragment demonstrates a trivial compression
+ * and decompression of a string using {@code Deflater} and
+ * {@code Inflater}.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *     compresser.end();
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch (java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @apiNote
+ * To release resources used by this {@code Deflater}, the {@link #end()} method
+ * should be called explicitly. Subclasses are responsible for the cleanup of resources
+ * acquired by the subclass. Subclasses that override {@link #finalize()} in order
+ * to perform cleanup should be modified to use alternative cleanup mechanisms such
+ * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ * @since 1.1
+ */
+
+public class Deflater {
+
+    private final DeflaterZStreamRef zsRef;
+    private ByteBuffer input = ZipUtils.defaultBuf;
+    private byte[] inputArray;
+    private int inputPos, inputLim;
+    private int level, strategy;
+    private boolean setParams;
+    private boolean finish, finished;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /**
+     * Compression method for the deflate algorithm (the only one currently
+     * supported).
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * Compression level for no compression.
+     */
+    public static final int NO_COMPRESSION = 0;
+
+    /**
+     * Compression level for fastest compression.
+     */
+    public static final int BEST_SPEED = 1;
+
+    /**
+     * Compression level for best compression.
+     */
+    public static final int BEST_COMPRESSION = 9;
+
+    /**
+     * Default compression level.
+     */
+    public static final int DEFAULT_COMPRESSION = -1;
+
+    /**
+     * Compression strategy best used for data consisting mostly of small
+     * values with a somewhat random distribution. Forces more Huffman coding
+     * and less string matching.
+     */
+    public static final int FILTERED = 1;
+
+    /**
+     * Compression strategy for Huffman coding only.
+     */
+    public static final int HUFFMAN_ONLY = 2;
+
+    /**
+     * Default compression strategy.
+     */
+    public static final int DEFAULT_STRATEGY = 0;
+
+    /**
+     * Compression flush mode used to achieve best compression result.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int NO_FLUSH = 0;
+
+    /**
+     * Compression flush mode used to flush out all pending output; may
+     * degrade compression for some compression algorithms.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int SYNC_FLUSH = 2;
+
+    /**
+     * Compression flush mode used to flush out all pending output and
+     * reset the deflater. Using this mode too often can seriously degrade
+     * compression.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int FULL_FLUSH = 3;
+
+    /**
+     * Flush mode to use at the end of output.  Can only be provided by the
+     * user by way of {@link #finish()}.
+     */
+    private static final int FINISH = 4;
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        ZipUtils.loadLibrary();
+    }
+    */
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * If 'nowrap' is true then the ZLIB header and checksum fields will
+     * not be used in order to support the compression format used in
+     * both GZIP and PKZIP.
+     * @param level the compression level (0-9)
+     * @param nowrap if true then use GZIP compatible compression
+     */
+    public Deflater(int level, boolean nowrap) {
+        this.level = level;
+        this.strategy = DEFAULT_STRATEGY;
+        this.zsRef = new DeflaterZStreamRef(this,
+                init(level, DEFAULT_STRATEGY, nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * Compressed data will be generated in ZLIB format.
+     * @param level the compression level (0-9)
+     */
+    public Deflater(int level) {
+        this(level, false);
+    }
+
+    /**
+     * Creates a new compressor with the default compression level.
+     * Compressed data will be generated in ZLIB format.
+     */
+    public Deflater() {
+        this(DEFAULT_COMPRESSION, false);
+    }
+
+    /**
+     * Sets input data for compression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     * @param input the input data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] input, int off, int len) {
+        if (off < 0 || len < 0 || off > input.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.input = null;
+            this.inputArray = input;
+            this.inputPos = off;
+            this.inputLim = off + len;
+        }
+    }
+
+    /**
+     * Sets input data for compression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     * @param input the input data bytes
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] input) {
+        setInput(input, 0, input.length);
+    }
+
+    /**
+     * Sets input data for compression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     * <p>
+     * The given buffer's position will be advanced as deflate
+     * operations are performed, up to the buffer's limit.
+     * The input buffer may be modified (refilled) between deflate
+     * operations; doing so is equivalent to creating a new buffer
+     * and setting it with this method.
+     * <p>
+     * Modifying the input buffer's contents, position, or limit
+     * concurrently with an deflate operation will result in
+     * undefined behavior, which may include incorrect operation
+     * results or operation failure.
+     *
+     * @param input the input data bytes
+     * @see Deflater#needsInput
+     * @since 11
+     */
+    public void setInput(ByteBuffer input) {
+        Objects.requireNonNull(input);
+        synchronized (zsRef) {
+            this.input = input;
+            this.inputArray = null;
+        }
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param dictionary the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] dictionary, int off, int len) {
+        if (off < 0 || len < 0 || off > dictionary.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), dictionary, off, len);
+        }
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param dictionary the dictionary data bytes
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] dictionary) {
+        setDictionary(dictionary, 0, dictionary.length);
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * <p>
+     * The bytes in given byte buffer will be fully consumed by this method.  On
+     * return, its position will equal its limit.
+     *
+     * @param dictionary the dictionary data bytes
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(ByteBuffer dictionary) {
+        synchronized (zsRef) {
+            int position = dictionary.position();
+            int remaining = Math.max(dictionary.limit() - position, 0);
+            ensureOpen();
+            if (dictionary.isDirect()) {
+                long address = ((DirectBuffer) dictionary).address();
+                try {
+                    setDictionaryBuffer(zsRef.address(), address + position, remaining);
+                } finally {
+                    Reference.reachabilityFence(dictionary);
+                }
+            } else {
+                byte[] array = ZipUtils.getBufferArray(dictionary);
+                int offset = ZipUtils.getBufferOffset(dictionary);
+                setDictionary(zsRef.address(), array, offset + position, remaining);
+            }
+            dictionary.position(position + remaining);
+        }
+    }
+
+    /**
+     * Sets the compression strategy to the specified value.
+     *
+     * <p> If the compression strategy is changed, the next invocation
+     * of {@code deflate} will compress the input available so far with
+     * the old strategy (and may be flushed); the new strategy will take
+     * effect only after that invocation.
+     *
+     * @param strategy the new compression strategy
+     * @throws    IllegalArgumentException if the compression strategy is
+     *                                     invalid
+     */
+    public void setStrategy(int strategy) {
+        switch (strategy) {
+          case DEFAULT_STRATEGY:
+          case FILTERED:
+          case HUFFMAN_ONLY:
+            break;
+          default:
+            throw new IllegalArgumentException();
+        }
+        synchronized (zsRef) {
+            if (this.strategy != strategy) {
+                this.strategy = strategy;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Sets the compression level to the specified value.
+     *
+     * <p> If the compression level is changed, the next invocation
+     * of {@code deflate} will compress the input available so far
+     * with the old level (and may be flushed); the new level will
+     * take effect only after that invocation.
+     *
+     * @param level the new compression level (0-9)
+     * @throws    IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
+            throw new IllegalArgumentException("invalid compression level");
+        }
+        synchronized (zsRef) {
+            if (this.level != level) {
+                this.level = level;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Returns true if no data remains in the input buffer. This can
+     * be used to determine if one of the {@code setInput()} methods should be
+     * called in order to provide more input.
+     *
+     * @return true if the input data buffer is empty and setInput()
+     * should be called in order to provide more input
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            ByteBuffer input = this.input;
+            return input == null ? inputLim == inputPos : ! input.hasRemaining();
+        }
+    }
+
+    /**
+     * When called, indicates that compression should end with the current
+     * contents of the input buffer.
+     */
+    public void finish() {
+        synchronized (zsRef) {
+            finish = true;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data output stream has
+     * been reached.
+     * @return true if the end of the compressed data output stream has
+     * been reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b, off, len)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
+     *
+     * @param output the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] output, int off, int len) {
+        return deflate(output, off, len, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
+     *
+     * @param output the buffer for the compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] output) {
+        return deflate(output, 0, output.length, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(output)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(output, Deflater.NO_FLUSH)}.
+     *
+     * @param output the buffer for the compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     * @since 11
+     */
+    public int deflate(ByteBuffer output) {
+        return deflate(output, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills the specified buffer with compressed
+     * data. Returns actual number of bytes of data compressed.
+     *
+     * <p>Compression flush mode is one of the following three modes:
+     *
+     * <ul>
+     * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+     * to accumulate, before producing output, in order to achieve the best
+     * compression (should be used in normal use scenario). A return value
+     * of 0 in this flush mode indicates that {@link #needsInput()} should
+     * be called in order to determine if more input data is required.
+     *
+     * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+     * to the specified output buffer, so that an inflater that works on
+     * compressed data can get all input data available so far (In particular
+     * the {@link #needsInput()} returns {@code true} after this invocation
+     * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+     * may degrade compression for some compression algorithms and so it
+     * should be used only when necessary.
+     *
+     * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+     * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+     * that works on the compressed output data can restart from this point
+     * if previous compressed data has been damaged or if random access is
+     * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+     * compression.
+     * </ul>
+     *
+     * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+     * the return value is {@code len}, the space available in output
+     * buffer {@code b}, this method should be invoked again with the same
+     * {@code flush} parameter and more output space. Make sure that
+     * {@code len} is greater than 6 to avoid flush marker (5 bytes) being
+     * repeatedly output to the output buffer every time this method is
+     * invoked.
+     *
+     * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+     * for input, the input buffer's position will be advanced by the number of bytes
+     * consumed by this operation.
+     *
+     * @param output the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @param flush the compression flush mode
+     * @return the actual number of bytes of compressed data written to
+     *         the output buffer
+     *
+     * @throws IllegalArgumentException if the flush mode is invalid
+     * @since 1.7
+     */
+    public int deflate(byte[] output, int off, int len, int flush) {
+        if (off < 0 || len < 0 || off > output.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
+            throw new IllegalArgumentException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+
+            ByteBuffer input = this.input;
+            if (finish) {
+                // disregard given flush mode in this case
+                flush = FINISH;
+            }
+            int params;
+            if (setParams) {
+                // bit 0: true to set params
+                // bit 1-2: strategy (0, 1, or 2)
+                // bit 3-31: level (0..9 or -1)
+                params = 1 | strategy << 1 | level << 3;
+            } else {
+                params = 0;
+            }
+            int inputPos;
+            long result;
+            if (input == null) {
+                inputPos = this.inputPos;
+                result = deflateBytesBytes(zsRef.address(),
+                    inputArray, inputPos, inputLim - inputPos,
+                    output, off, len,
+                    flush, params);
+            } else {
+                inputPos = input.position();
+                int inputRem = Math.max(input.limit() - inputPos, 0);
+                if (input.isDirect()) {
+                    try {
+                        long inputAddress = ((DirectBuffer) input).address();
+                        result = deflateBufferBytes(zsRef.address(),
+                            inputAddress + inputPos, inputRem,
+                            output, off, len,
+                            flush, params);
+                    } finally {
+                        Reference.reachabilityFence(input);
+                    }
+                } else {
+                    byte[] inputArray = ZipUtils.getBufferArray(input);
+                    int inputOffset = ZipUtils.getBufferOffset(input);
+                    result = deflateBytesBytes(zsRef.address(),
+                        inputArray, inputOffset + inputPos, inputRem,
+                        output, off, len,
+                        flush, params);
+                }
+            }
+            int read = (int) (result & 0x7fff_ffffL);
+            int written = (int) (result >>> 31 & 0x7fff_ffffL);
+            if ((result >>> 62 & 1) != 0) {
+                finished = true;
+            }
+            if (params != 0 && (result >>> 63 & 1) == 0) {
+                setParams = false;
+            }
+            if (input != null) {
+                input.position(inputPos + read);
+            } else {
+                this.inputPos = inputPos + read;
+            }
+            bytesWritten += written;
+            bytesRead += read;
+            return written;
+        }
+    }
+
+    /**
+     * Compresses the input data and fills the specified buffer with compressed
+     * data. Returns actual number of bytes of data compressed.
+     *
+     * <p>Compression flush mode is one of the following three modes:
+     *
+     * <ul>
+     * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+     * to accumulate, before producing output, in order to achieve the best
+     * compression (should be used in normal use scenario). A return value
+     * of 0 in this flush mode indicates that {@link #needsInput()} should
+     * be called in order to determine if more input data is required.
+     *
+     * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+     * to the specified output buffer, so that an inflater that works on
+     * compressed data can get all input data available so far (In particular
+     * the {@link #needsInput()} returns {@code true} after this invocation
+     * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+     * may degrade compression for some compression algorithms and so it
+     * should be used only when necessary.
+     *
+     * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+     * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+     * that works on the compressed output data can restart from this point
+     * if previous compressed data has been damaged or if random access is
+     * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+     * compression.
+     * </ul>
+     *
+     * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+     * the return value is equal to the {@linkplain ByteBuffer#remaining() remaining space}
+     * of the buffer, this method should be invoked again with the same
+     * {@code flush} parameter and more output space. Make sure that
+     * the buffer has at least 6 bytes of remaining space to avoid the
+     * flush marker (5 bytes) being repeatedly output to the output buffer
+     * every time this method is invoked.
+     *
+     * <p>On success, the position of the given {@code output} byte buffer will be
+     * advanced by as many bytes as were produced by the operation, which is equal
+     * to the number returned by this method.
+     *
+     * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+     * for input, the input buffer's position will be advanced by the number of bytes
+     * consumed by this operation.
+     *
+     * @param output the buffer for the compressed data
+     * @param flush the compression flush mode
+     * @return the actual number of bytes of compressed data written to
+     *         the output buffer
+     *
+     * @throws IllegalArgumentException if the flush mode is invalid
+     * @since 11
+     */
+    public int deflate(ByteBuffer output, int flush) {
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
+            throw new IllegalArgumentException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+
+            ByteBuffer input = this.input;
+            if (finish) {
+                // disregard given flush mode in this case
+                flush = FINISH;
+            }
+            int params;
+            if (setParams) {
+                // bit 0: true to set params
+                // bit 1-2: strategy (0, 1, or 2)
+                // bit 3-31: level (0..9 or -1)
+                params = 1 | strategy << 1 | level << 3;
+            } else {
+                params = 0;
+            }
+            int outputPos = output.position();
+            int outputRem = Math.max(output.limit() - outputPos, 0);
+            int inputPos;
+            long result;
+            if (input == null) {
+                inputPos = this.inputPos;
+                if (output.isDirect()) {
+                    long outputAddress = ((DirectBuffer) output).address();
+                    try {
+                        result = deflateBytesBuffer(zsRef.address(),
+                            inputArray, inputPos, inputLim - inputPos,
+                            outputAddress + outputPos, outputRem,
+                            flush, params);
+                    } finally {
+                        Reference.reachabilityFence(output);
+                    }
+                } else {
+                    byte[] outputArray = ZipUtils.getBufferArray(output);
+                    int outputOffset = ZipUtils.getBufferOffset(output);
+                    result = deflateBytesBytes(zsRef.address(),
+                        inputArray, inputPos, inputLim - inputPos,
+                        outputArray, outputOffset + outputPos, outputRem,
+                        flush, params);
+                }
+            } else {
+                inputPos = input.position();
+                int inputRem = Math.max(input.limit() - inputPos, 0);
+                if (input.isDirect()) {
+                    long inputAddress = ((DirectBuffer) input).address();
+                    try {
+                        if (output.isDirect()) {
+                            long outputAddress = outputPos + ((DirectBuffer) output).address();
+                            try {
+                                result = deflateBufferBuffer(zsRef.address(),
+                                    inputAddress + inputPos, inputRem,
+                                    outputAddress, outputRem,
+                                    flush, params);
+                            } finally {
+                                Reference.reachabilityFence(output);
+                            }
+                        } else {
+                            byte[] outputArray = ZipUtils.getBufferArray(output);
+                            int outputOffset = ZipUtils.getBufferOffset(output);
+                            result = deflateBufferBytes(zsRef.address(),
+                                inputAddress + inputPos, inputRem,
+                                outputArray, outputOffset + outputPos, outputRem,
+                                flush, params);
+                        }
+                    } finally {
+                        Reference.reachabilityFence(input);
+                    }
+                } else {
+                    byte[] inputArray = ZipUtils.getBufferArray(input);
+                    int inputOffset = ZipUtils.getBufferOffset(input);
+                    if (output.isDirect()) {
+                        long outputAddress = ((DirectBuffer) output).address();
+                        try {
+                            result = deflateBytesBuffer(zsRef.address(),
+                                inputArray, inputOffset + inputPos, inputRem,
+                                outputAddress + outputPos, outputRem,
+                                flush, params);
+                        } finally {
+                            Reference.reachabilityFence(output);
+                        }
+                    } else {
+                        byte[] outputArray = ZipUtils.getBufferArray(output);
+                        int outputOffset = ZipUtils.getBufferOffset(output);
+                        result = deflateBytesBytes(zsRef.address(),
+                            inputArray, inputOffset + inputPos, inputRem,
+                            outputArray, outputOffset + outputPos, outputRem,
+                            flush, params);
+                    }
+                }
+            }
+            int read = (int) (result & 0x7fff_ffffL);
+            int written = (int) (result >>> 31 & 0x7fff_ffffL);
+            if ((result >>> 62 & 1) != 0) {
+                finished = true;
+            }
+            if (params != 0 && (result >>> 63 & 1) == 0) {
+                setParams = false;
+            }
+            if (input != null) {
+                input.position(inputPos + read);
+            } else {
+                this.inputPos = inputPos + read;
+            }
+            output.position(outputPos + written);
+            bytesWritten += written;
+            bytesRead += read;
+            return written;
+        }
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * @return the total (non-negative) number of compressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets deflater so that a new set of input data can be processed.
+     * Keeps current compression level and strategy settings.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            finish = false;
+            finished = false;
+            input = ZipUtils.defaultBuf;
+            inputArray = null;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the compressor and discards any unprocessed input.
+     *
+     * This method should be called when the compressor is no longer
+     * being used. Once this method is called, the behavior of the
+     * Deflater object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            zsRef.clean();
+            // Android-added: CloseGuard support.
+            if (guard != null) {
+                guard.close();
+            }
+            input = ZipUtils.defaultBuf;
+        }
+    }
+
+    private void ensureOpen() {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Deflater has been closed");
+    }
+
+    /**
+     * Returns the value of 'finish' flag.
+     * 'finish' will be set to true if def.finish() method is called.
+     */
+    boolean shouldFinish() {
+        synchronized (zsRef) {
+            return finish;
+        }
+    }
+
+    private static native long init(int level, int strategy, boolean nowrap);
+    private static native void setDictionary(long addr, byte[] b, int off,
+                                             int len);
+    private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+    private native long deflateBytesBytes(long addr,
+        byte[] inputArray, int inputOff, int inputLen,
+        byte[] outputArray, int outputOff, int outputLen,
+        int flush, int params);
+    private native long deflateBytesBuffer(long addr,
+        byte[] inputArray, int inputOff, int inputLen,
+        long outputAddress, int outputLen,
+        int flush, int params);
+    private native long deflateBufferBytes(long addr,
+        long inputAddress, int inputLen,
+        byte[] outputArray, int outputOff, int outputLen,
+        int flush, int params);
+    private native long deflateBufferBuffer(long addr,
+        long inputAddress, int inputLen,
+        long outputAddress, int outputLen,
+        int flush, int params);
+    private static native int getAdler(long addr);
+    private static native void reset(long addr);
+    private static native void end(long addr);
+
+    /**
+     * A reference to the native zlib's z_stream structure. It also
+     * serves as the "cleaner" to clean up the native resource when
+     * the Deflater is ended, closed or cleaned.
+     */
+    static class DeflaterZStreamRef implements Runnable {
+
+        private long address;
+        private final Cleanable cleanable;
+
+        private DeflaterZStreamRef(Deflater owner, long addr) {
+            this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
+            this.address = addr;
+        }
+
+        long address() {
+            return address;
+        }
+
+        void clean() {
+            cleanable.clean();
+        }
+
+        public synchronized void run() {
+            long addr = address;
+            address = 0;
+            if (addr != 0) {
+                end(addr);
+            }
+        }
+
+    }
+}
diff --git a/android-35/java/util/zip/DeflaterInputStream.java b/android-35/java/util/zip/DeflaterInputStream.java
new file mode 100644
index 0000000..1408c61
--- /dev/null
+++ b/android-35/java/util/zip/DeflaterInputStream.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Implements an input stream filter for compressing data in the "deflate"
+ * compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see DeflaterOutputStream
+ * @see InflaterOutputStream
+ * @see InflaterInputStream
+ */
+
+public class DeflaterInputStream extends FilterInputStream {
+    /** Compressor for this stream. */
+    protected final Deflater def;
+
+    /** Input buffer for reading compressed data. */
+    protected final byte[] buf;
+
+    /** Temporary read buffer. */
+    private byte[] rbuf = new byte[1];
+
+    /** Default compressor is used. */
+    private boolean usesDefaultDeflater = false;
+
+    /** End of the underlying input stream has been reached. */
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with a default compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @throws NullPointerException if {@code in} is null
+     */
+    public DeflaterInputStream(InputStream in) {
+        this(in, in != null ? new Deflater() : null);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and a
+     * default buffer size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl) {
+        this(in, defl, 512);
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @param bufLen compression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) {
+        super(in);
+
+        // Sanity checks
+        if (in == null)
+            throw new NullPointerException("Null input");
+        if (defl == null)
+            throw new NullPointerException("Null deflater");
+        if (bufLen < 1)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        def = defl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Closes this input stream and its underlying input stream, discarding
+     * any pending uncompressed data.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (in != null) {
+            try {
+                // Clean up
+                if (usesDefaultDeflater) {
+                    def.end();
+                }
+
+                in.close();
+            } finally {
+                in = null;
+            }
+        }
+    }
+
+    /**
+     * Reads a single byte of compressed data from the input stream.
+     * This method will block until some input can be read and compressed.
+     *
+     * @return a single byte of compressed data, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int read() throws IOException {
+        // Read a single byte of compressed data
+        int len = read(rbuf, 0, 1);
+        if (len <= 0)
+            return -1;
+        return (rbuf[0] & 0xFF);
+    }
+
+    /**
+     * Reads compressed data into a byte array.
+     * This method will block until some input can be read and compressed.
+     *
+     * @param b buffer into which the data is read
+     * @param off starting offset of the data within {@code b}
+     * @param len maximum number of compressed bytes to read into {@code b}
+     * @return the actual number of bytes read, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IndexOutOfBoundsException  if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or if this input stream is
+     * already closed
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        // Read and compress (deflate) input data bytes
+        int cnt = 0;
+        while (len > 0 && !def.finished()) {
+            int n;
+
+            // Read data from the input stream
+            if (def.needsInput()) {
+                n = in.read(buf, 0, buf.length);
+                if (n < 0) {
+                    // End of the input stream reached
+                    def.finish();
+                } else if (n > 0) {
+                    def.setInput(buf, 0, n);
+                }
+            }
+
+            // Compress the input data, filling the read buffer
+            n = def.deflate(b, off, len);
+            cnt += n;
+            off += n;
+            len -= n;
+        }
+        // BEGIN Android-changed: Return more accurate value from available().
+        // Set reachEOF eagerly when the Deflater has finished, and not just when the number of
+        // bytes is zero so that available is more accurate.
+        // See http://b/111589691
+        /*
+        if (cnt == 0 && def.finished()) {
+            reachEOF = true;
+            cnt = -1;
+        }
+        */
+        if (def.finished()) {
+            reachEOF = true;
+            if (cnt == 0) {
+                cnt = -1;
+            }
+        }
+        // END Android-changed: Return more accurate value from available().
+
+        return cnt;
+    }
+
+    /**
+     * Skips over and discards data from the input stream.
+     * This method may block until the specified number of bytes are read and
+     * skipped. <em>Note:</em> While {@code n} is given as a {@code long},
+     * the maximum number of bytes which can be skipped is
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @param n number of bytes to be skipped
+     * @return the actual number of bytes skipped
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+
+        // Skip bytes by repeatedly decompressing small blocks
+        if (rbuf.length < 512)
+            rbuf = new byte[512];
+
+        int total = (int)Math.min(n, Integer.MAX_VALUE);
+        long cnt = 0;
+        while (total > 0) {
+            // Read a small block of uncompressed bytes
+            int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
+
+            if (len < 0) {
+                break;
+            }
+            cnt += len;
+            total -= len;
+        }
+        return cnt;
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking
+     * @return zero after the end of the underlying input stream has been
+     * reached, otherwise always returns 1
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        }
+        return 1;
+    }
+
+    /**
+     * Always returns {@code false} because this input stream does not support
+     * the {@link #mark mark()} and {@link #reset reset()} methods.
+     *
+     * @return false, always
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @param limit maximum bytes that can be read before invalidating the position marker
+     */
+    public void mark(int limit) {
+        // Operation not supported
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @throws IOException always thrown
+     */
+    public void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/android-35/java/util/zip/DeflaterOutputStream.java b/android-35/java/util/zip/DeflaterOutputStream.java
new file mode 100644
index 0000000..8f3379f
--- /dev/null
+++ b/android-35/java/util/zip/DeflaterOutputStream.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class implements an output stream filter for compressing data in
+ * the "deflate" compression format. It is also used as the basis for other
+ * types of compression filters, such as GZIPOutputStream.
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class DeflaterOutputStream extends FilterOutputStream {
+    /**
+     * Compressor for this stream.
+     */
+    protected Deflater def;
+
+    /**
+     * Output buffer for writing compressed data.
+     */
+    protected byte[] buf;
+
+    /**
+     * Indicates that the stream has been closed.
+     */
+    private boolean closed = false;
+
+    private final boolean syncFlush;
+
+    /**
+     * Creates a new output stream with the specified compressor,
+     * buffer size and flush mode.
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @throws IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                int size,
+                                boolean syncFlush) {
+        super(out);
+        if (out == null || def == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.def = def;
+        this.buf = new byte[size];
+        this.syncFlush = syncFlush;
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 4-argument constructor DeflaterOutputStream(out, def, size, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
+        this(out, def, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified compressor, flush
+     * mode and a default buffer size.
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                boolean syncFlush) {
+        this(out, def, 512, syncFlush);
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor DeflaterOutputStream(out, def, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def) {
+        this(out, def, 512, false);
+    }
+
+    boolean usesDefaultDeflater = false;
+
+
+    /**
+     * Creates a new output stream with a default compressor, a default
+     * buffer size and the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out, boolean syncFlush) {
+        this(out, out != null ? new Deflater() : null, 512, syncFlush);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new output stream with a default compressor and buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor DeflaterOutputStream(out, false).
+     *
+     * @param out the output stream
+     */
+    public DeflaterOutputStream(OutputStream out) {
+        this(out, false);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Writes a byte to the compressed output stream. This method will
+     * block until the byte can be written.
+     * @param b the byte to be written
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        byte[] buf = new byte[1];
+        buf[0] = (byte)(b & 0xff);
+        write(buf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the compressed output stream. This
+     * method will block until all the bytes are written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (def.finished()) {
+            throw new IOException("write beyond end of stream");
+        }
+        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        if (!def.finished()) {
+            def.setInput(b, off, len);
+            while (!def.needsInput()) {
+                deflate();
+            }
+        }
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            try{
+                def.finish();
+                while (!def.finished()) {
+                    deflate();
+                }
+            } catch(IOException e) {
+                if (usesDefaultDeflater)
+                    def.end();
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * Writes remaining compressed data to the output stream and closes the
+     * underlying stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            try {
+                finish();
+            } finally {
+                if (usesDefaultDeflater)
+                    def.end();
+            }
+            out.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Writes next block of compressed data to the output stream.
+     * @throws IOException if an I/O error has occurred
+     */
+    protected void deflate() throws IOException {
+        // Android-changed: Output all available compressed data (b/4005091).
+        // See http://b/111496419 for more details.
+        // int len = def.deflate(buf, 0, buf.length);
+        // if (len > 0) {
+        //     out.write(buf, 0, len);
+        // }
+        int len = 0;
+        while ((len = def.deflate(buf, 0, buf.length)) > 0) {
+          out.write(buf, 0, len);
+        }
+    }
+
+    /**
+     * Flushes the compressed output stream.
+     *
+     * If {@link #DeflaterOutputStream(OutputStream, Deflater, int, boolean)
+     * syncFlush} is {@code true} when this compressed output stream is
+     * constructed, this method first flushes the underlying {@code compressor}
+     * with the flush mode {@link Deflater#SYNC_FLUSH} to force
+     * all pending data to be flushed out to the output stream and then
+     * flushes the output stream. Otherwise this method only flushes the
+     * output stream without flushing the {@code compressor}.
+     *
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public void flush() throws IOException {
+        if (syncFlush && !def.finished()) {
+            int len = 0;
+            while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0)
+            {
+                out.write(buf, 0, len);
+                if (len < buf.length)
+                    break;
+            }
+        }
+        out.flush();
+    }
+}
diff --git a/android-35/java/util/zip/GZIPInputStream.java b/android-35/java/util/zip/GZIPInputStream.java
new file mode 100644
index 0000000..871e9d3
--- /dev/null
+++ b/android-35/java/util/zip/GZIPInputStream.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.SequenceInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for reading compressed data in
+ * the GZIP file format.
+ *
+ * @see         InflaterInputStream
+ * @author      David Connelly
+ * @since 1.1
+ *
+ */
+public class GZIPInputStream extends InflaterInputStream {
+    /**
+     * CRC-32 for uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /**
+     * Indicates end of input stream.
+     */
+    protected boolean eos;
+
+    private boolean closed = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with the specified buffer size.
+     *
+     * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+     * consider using buffered inputs with this class. More information can be found in the
+     * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+     * UnbufferedIO</a> and
+     * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+     * documentation.
+     *
+     * @param in the input stream
+     * @param size the input buffer size
+     *
+     * @throws    ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @throws    IOException if an I/O error has occurred
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPInputStream(InputStream in, int size) throws IOException {
+        super(in, in != null ? new Inflater(true) : null, size);
+        // Android-removed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        // BEGIN Android-changed: Do not rely on finalization to inf.end().
+        // readHeader(in);
+        try {
+            readHeader(in);
+        } catch (Exception e) {
+            inf.end();
+            throw e;
+        }
+        // END Android-changed: Do not rely on finalization to inf.end().
+    }
+
+    /**
+     * Creates a new input stream with a default buffer size.
+     * @param in the input stream
+     *
+     * @throws    ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @throws    IOException if an I/O error has occurred
+     */
+    public GZIPInputStream(InputStream in) throws IOException {
+        this(in, 512);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If {@code len} is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and {@code 0} is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array {@code b}
+     * @param len the maximum number of bytes read
+     * @return  the actual number of bytes read, or -1 if the end of the
+     *          compressed input stream is reached
+     *
+     * @throws     NullPointerException If {@code buf} is {@code null}.
+     * @throws     IndexOutOfBoundsException If {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code buf.length - off}
+     * @throws    ZipException if the compressed input data is corrupt.
+     * @throws    IOException if an I/O error has occurred.
+     *
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        ensureOpen();
+        if (eos) {
+            return -1;
+        }
+        int n = super.read(buf, off, len);
+        if (n == -1) {
+            if (readTrailer())
+                eos = true;
+            else
+                return this.read(buf, off, len);
+        } else {
+            crc.update(buf, off, n);
+        }
+        return n;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            eos = true;
+            closed = true;
+        }
+    }
+
+    /**
+     * GZIP header magic number.
+     */
+    public static final int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * File header flags.
+     */
+    private static final int FTEXT      = 1;    // Extra text
+    private static final int FHCRC      = 2;    // Header CRC
+    private static final int FEXTRA     = 4;    // Extra field
+    private static final int FNAME      = 8;    // File name
+    private static final int FCOMMENT   = 16;   // File comment
+
+    /*
+     * Reads GZIP member header and returns the total byte number
+     * of this member header.
+     */
+    private int readHeader(InputStream this_in) throws IOException {
+        CheckedInputStream in = new CheckedInputStream(this_in, crc);
+        crc.reset();
+        // Check header magic
+        if (readUShort(in) != GZIP_MAGIC) {
+            throw new ZipException("Not in GZIP format");
+        }
+        // Check compression method
+        if (readUByte(in) != 8) {
+            throw new ZipException("Unsupported compression method");
+        }
+        // Read flags
+        int flg = readUByte(in);
+        // Skip MTIME, XFL, and OS fields
+        skipBytes(in, 6);
+        int n = 2 + 2 + 6;
+        // Skip optional extra field
+        if ((flg & FEXTRA) == FEXTRA) {
+            int m = readUShort(in);
+            skipBytes(in, m);
+            n += m + 2;
+        }
+        // Skip optional file name
+        if ((flg & FNAME) == FNAME) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Skip optional file comment
+        if ((flg & FCOMMENT) == FCOMMENT) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Check optional header CRC
+        if ((flg & FHCRC) == FHCRC) {
+            int v = (int)crc.getValue() & 0xffff;
+            if (readUShort(in) != v) {
+                throw new ZipException("Corrupt GZIP header");
+            }
+            n += 2;
+        }
+        crc.reset();
+        return n;
+    }
+
+    /*
+     * Reads GZIP member trailer and returns true if the eos
+     * reached, false if there are more (concatenated gzip
+     * data set)
+     */
+    private boolean readTrailer() throws IOException {
+        InputStream in = this.in;
+        int n = inf.getRemaining();
+        if (n > 0) {
+            in = new SequenceInputStream(
+                        new ByteArrayInputStream(buf, len - n, n),
+                        new FilterInputStream(in) {
+                            public void close() throws IOException {}
+                        });
+        }
+        // Uses left-to-right evaluation order
+        if ((readUInt(in) != crc.getValue()) ||
+            // rfc1952; ISIZE is the input size modulo 2^32
+            (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL)))
+            throw new ZipException("Corrupt GZIP trailer");
+
+        // If there are more bytes available in "in" or
+        // the leftover in the "inf" is > 26 bytes:
+        // this.trailer(8) + next.header.min(10) + next.trailer(8)
+        // try concatenated case
+        if (this.in.available() > 0 || n > 26) {
+            int m = 8;                  // this.trailer
+            try {
+                m += readHeader(in);    // next.header
+            } catch (IOException ze) {
+                return true;  // ignore any malformed, do nothing
+            }
+            inf.reset();
+            if (n > m)
+                inf.setInput(buf, len - n + m, n - m);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Reads unsigned integer in Intel byte order.
+     */
+    private long readUInt(InputStream in) throws IOException {
+        long s = readUShort(in);
+        return ((long)readUShort(in) << 16) | s;
+    }
+
+    /*
+     * Reads unsigned short in Intel byte order.
+     */
+    private int readUShort(InputStream in) throws IOException {
+        int b = readUByte(in);
+        return (readUByte(in) << 8) | b;
+    }
+
+    /*
+     * Reads unsigned byte.
+     */
+    private int readUByte(InputStream in) throws IOException {
+        int b = in.read();
+        if (b == -1) {
+            throw new EOFException();
+        }
+        if (b < -1 || b > 255) {
+            // Report on this.in, not argument in; see read{Header, Trailer}.
+            throw new IOException(this.in.getClass().getName()
+                + ".read() returned value out of range -1..255: " + b);
+        }
+        return b;
+    }
+
+    private byte[] tmpbuf = new byte[128];
+
+    /*
+     * Skips bytes of input data blocking until all bytes are skipped.
+     * Does not assume that the input stream is capable of seeking.
+     */
+    private void skipBytes(InputStream in, int n) throws IOException {
+        while (n > 0) {
+            int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length);
+            if (len == -1) {
+                throw new EOFException();
+            }
+            n -= len;
+        }
+    }
+}
diff --git a/android-35/java/util/zip/GZIPOutputStream.java b/android-35/java/util/zip/GZIPOutputStream.java
new file mode 100644
index 0000000..6752092
--- /dev/null
+++ b/android-35/java/util/zip/GZIPOutputStream.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class implements a stream filter for writing compressed data in
+ * the GZIP file format.
+ * @author      David Connelly
+ * @since 1.1
+ *
+ */
+public class GZIPOutputStream extends DeflaterOutputStream {
+    /**
+     * CRC-32 of uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /*
+     * GZIP header magic number.
+     */
+    private static final int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * Trailer size in bytes.
+     *
+     */
+    private static final int TRAILER_SIZE = 8;
+
+    // Represents the default "unknown" value for OS header, per RFC-1952
+    private static final byte OS_UNKNOWN = (byte) 255;
+
+    /**
+     * Creates a new output stream with the specified buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor GZIPOutputStream(out, size, false).
+     *
+     * Android-note: Android limits the number of UnbufferedIO operations that can be performed, so
+     * consider using buffered inputs with this class. More information can be found in the
+     * <a href="https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder#detectUnbufferedIo()">
+     * UnbufferedIO</a> and
+     * <a href="https://developer.android.com/reference/android/os/StrictMode"> StrictMode</a>
+     * documentation.
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @throws    IOException If an I/O error has occurred.
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPOutputStream(OutputStream out, int size) throws IOException {
+        this(out, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified buffer size and
+     * flush mode.
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     * @throws    IOException If an I/O error has occurred.
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, int size, boolean syncFlush)
+        throws IOException
+    {
+        super(out, out != null ? new Deflater(Deflater.DEFAULT_COMPRESSION, true) : null,
+              size,
+              syncFlush);
+        usesDefaultDeflater = true;
+        writeHeader();
+        crc.reset();
+    }
+
+
+    /**
+     * Creates a new output stream with a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor GZIPOutputStream(out, false).
+     *
+     * @param out the output stream
+     * @throws    IOException If an I/O error has occurred.
+     */
+    public GZIPOutputStream(OutputStream out) throws IOException {
+        this(out, 512, false);
+    }
+
+    /**
+     * Creates a new output stream with a default buffer size and
+     * the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @throws    IOException If an I/O error has occurred.
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, boolean syncFlush)
+        throws IOException
+    {
+        this(out, 512, syncFlush);
+    }
+
+    /**
+     * Writes array of bytes to the compressed output stream. This method
+     * will block until all the bytes are written.
+     * @param buf the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @throws    IOException If an I/O error has occurred.
+     */
+    public synchronized void write(byte[] buf, int off, int len)
+        throws IOException
+    {
+        super.write(buf, off, len);
+        crc.update(buf, off, len);
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            try {
+                def.finish();
+                while (!def.finished()) {
+                    int len = def.deflate(buf, 0, buf.length);
+                    if (def.finished() && len <= buf.length - TRAILER_SIZE) {
+                        // last deflater buffer. Fit trailer at the end
+                        writeTrailer(buf, len);
+                        len = len + TRAILER_SIZE;
+                        out.write(buf, 0, len);
+                        return;
+                    }
+                    if (len > 0)
+                        out.write(buf, 0, len);
+                }
+                // if we can't fit the trailer at the end of the last
+                // deflater buffer, we write it separately
+                byte[] trailer = new byte[TRAILER_SIZE];
+                writeTrailer(trailer, 0);
+                out.write(trailer);
+            } catch (IOException e) {
+                if (usesDefaultDeflater)
+                    def.end();
+                throw e;
+            }
+        }
+    }
+
+    /*
+     * Writes GZIP member header.
+     */
+    private void writeHeader() throws IOException {
+        out.write(new byte[] {
+                      (byte) GZIP_MAGIC,        // Magic number (short)
+                      (byte)(GZIP_MAGIC >> 8),  // Magic number (short)
+                      Deflater.DEFLATED,        // Compression method (CM)
+                      0,                        // Flags (FLG)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Extra flags (XFLG)
+                      OS_UNKNOWN                // Operating system (OS)
+                  });
+    }
+
+    /*
+     * Writes GZIP member trailer to a byte array, starting at a given
+     * offset.
+     */
+    private void writeTrailer(byte[] buf, int offset) throws IOException {
+        writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
+        writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
+    }
+
+    /*
+     * Writes integer in Intel byte order to a byte array, starting at a
+     * given offset.
+     */
+    private void writeInt(int i, byte[] buf, int offset) throws IOException {
+        writeShort(i & 0xffff, buf, offset);
+        writeShort((i >> 16) & 0xffff, buf, offset + 2);
+    }
+
+    /*
+     * Writes short integer in Intel byte order to a byte array, starting
+     * at a given offset
+     */
+    private void writeShort(int s, byte[] buf, int offset) throws IOException {
+        buf[offset] = (byte)(s & 0xff);
+        buf[offset + 1] = (byte)((s >> 8) & 0xff);
+    }
+}
diff --git a/android-35/java/util/zip/Inflater.java b/android-35/java/util/zip/Inflater.java
new file mode 100644
index 0000000..6e6c83e
--- /dev/null
+++ b/android-35/java/util/zip/Inflater.java
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
+import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * This class provides support for general purpose decompression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package-description">java.util.zip
+ * package description</a>.
+ * <p>
+ * This class inflates sequences of ZLIB compressed bytes. The input byte
+ * sequence is provided in either byte array or byte buffer, via one of the
+ * {@code setInput()} methods. The output byte sequence is written to the
+ * output byte array or byte buffer passed to the {@code deflate()} methods.
+ * <p>
+ * The following code fragment demonstrates a trivial compression
+ * and decompression of a string using {@code Deflater} and
+ * {@code Inflater}.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah\u20AC\u20AC";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch (java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @apiNote
+ * To release resources used by this {@code Inflater}, the {@link #end()} method
+ * should be called explicitly. Subclasses are responsible for the cleanup of resources
+ * acquired by the subclass. Subclasses that override {@link #finalize()} in order
+ * to perform cleanup should be modified to use alternative cleanup mechanisms such
+ * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ * @since 1.1
+ *
+ */
+
+public class Inflater {
+
+    private final InflaterZStreamRef zsRef;
+    private ByteBuffer input = ZipUtils.defaultBuf;
+    private byte[] inputArray;
+    private int inputPos, inputLim;
+    private boolean finished;
+    private boolean needDict;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /*
+     * These fields are used as an "out" parameter from JNI when a
+     * DataFormatException is thrown during the inflate operation.
+     */
+    private int inputConsumed;
+    private int outputConsumed;
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        ZipUtils.loadLibrary();
+        initIDs();
+    }
+    */
+
+    /**
+     * Creates a new decompressor. If the parameter 'nowrap' is true then
+     * the ZLIB header and checksum fields will not be used. This provides
+     * compatibility with the compression format used by both GZIP and PKZIP.
+     * <p>
+     * Note: When using the 'nowrap' option it is also necessary to provide
+     * an extra "dummy" byte as input. This is required by the ZLIB native
+     * library in order to support certain optimizations.
+     *
+     * @param nowrap if true then support GZIP compatible compression
+     */
+    public Inflater(boolean nowrap) {
+        this.zsRef = new InflaterZStreamRef(this, init(nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new decompressor.
+     */
+    public Inflater() {
+        this(false);
+    }
+
+    /**
+     * Sets input data for decompression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     *
+     * @param input the input data bytes
+     * @param off the start offset of the input data
+     * @param len the length of the input data
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] input, int off, int len) {
+        if (off < 0 || len < 0 || off > input.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.input = null;
+            this.inputArray = input;
+            this.inputPos = off;
+            this.inputLim = off + len;
+        }
+    }
+
+    /**
+     * Sets input data for decompression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     *
+     * @param input the input data bytes
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] input) {
+        setInput(input, 0, input.length);
+    }
+
+    /**
+     * Sets input data for decompression.
+     * <p>
+     * One of the {@code setInput()} methods should be called whenever
+     * {@code needsInput()} returns true indicating that more input data
+     * is required.
+     * <p>
+     * The given buffer's position will be advanced as inflate
+     * operations are performed, up to the buffer's limit.
+     * The input buffer may be modified (refilled) between inflate
+     * operations; doing so is equivalent to creating a new buffer
+     * and setting it with this method.
+     * <p>
+     * Modifying the input buffer's contents, position, or limit
+     * concurrently with an inflate operation will result in
+     * undefined behavior, which may include incorrect operation
+     * results or operation failure.
+     *
+     * @param input the input data bytes
+     * @see Inflater#needsInput
+     * @since 11
+     */
+    public void setInput(ByteBuffer input) {
+        Objects.requireNonNull(input);
+        synchronized (zsRef) {
+            this.input = input;
+            this.inputArray = null;
+        }
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param dictionary the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] dictionary, int off, int len) {
+        if (off < 0 || len < 0 || off > dictionary.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), dictionary, off, len);
+            needDict = false;
+        }
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param dictionary the dictionary data bytes
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] dictionary) {
+        setDictionary(dictionary, 0, dictionary.length);
+    }
+
+    /**
+     * Sets the preset dictionary to the bytes in the given buffer. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * <p>
+     * The bytes in given byte buffer will be fully consumed by this method.  On
+     * return, its position will equal its limit.
+     *
+     * @param dictionary the dictionary data bytes
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     * @since 11
+     */
+    public void setDictionary(ByteBuffer dictionary) {
+        synchronized (zsRef) {
+            int position = dictionary.position();
+            int remaining = Math.max(dictionary.limit() - position, 0);
+            ensureOpen();
+            if (dictionary.isDirect()) {
+                long address = ((DirectBuffer) dictionary).address();
+                try {
+                    setDictionaryBuffer(zsRef.address(), address + position, remaining);
+                } finally {
+                    Reference.reachabilityFence(dictionary);
+                }
+            } else {
+                byte[] array = ZipUtils.getBufferArray(dictionary);
+                int offset = ZipUtils.getBufferOffset(dictionary);
+                setDictionary(zsRef.address(), array, offset + position, remaining);
+            }
+            dictionary.position(position + remaining);
+            needDict = false;
+        }
+    }
+
+    /**
+     * Returns the total number of bytes remaining in the input buffer.
+     * This can be used to find out what bytes still remain in the input
+     * buffer after decompression has finished.
+     * @return the total number of bytes remaining in the input buffer
+     */
+    public int getRemaining() {
+        synchronized (zsRef) {
+            ByteBuffer input = this.input;
+            return input == null ? inputLim - inputPos : input.remaining();
+        }
+    }
+
+    /**
+     * Returns true if no data remains in the input buffer. This can
+     * be used to determine if one of the {@code setInput()} methods should be
+     * called in order to provide more input.
+     *
+     * @return true if no data remains in the input buffer
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            ByteBuffer input = this.input;
+            return input == null ? inputLim == inputPos : ! input.hasRemaining();
+        }
+    }
+
+    /**
+     * Returns true if a preset dictionary is needed for decompression.
+     * @return true if a preset dictionary is needed for decompression
+     * @see Inflater#setDictionary
+     */
+    public boolean needsDictionary() {
+        synchronized (zsRef) {
+            return needDict;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data stream has been
+     * reached.
+     * @return true if the end of the compressed data stream has been
+     * reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * <p>
+     * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+     * for input, the input buffer's position will be advanced by the number of bytes
+     * consumed by this operation, even in the event that a {@link DataFormatException}
+     * is thrown.
+     * <p>
+     * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+     * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
+     * method was called to provide a buffer for input, the input buffer's position
+     * will be advanced the number of consumed bytes.
+     * <p>
+     * These byte totals, as well as
+     * the {@linkplain #getBytesRead() total bytes read}
+     * and the {@linkplain #getBytesWritten() total bytes written}
+     * values, will be updated even in the event that a {@link DataFormatException}
+     * is thrown to reflect the amount of data consumed and produced before the
+     * exception occurred.
+     *
+     * @param output the buffer for the uncompressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of uncompressed bytes
+     * @return the actual number of uncompressed bytes
+     * @throws DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] output, int off, int len)
+        throws DataFormatException
+    {
+        if (off < 0 || len < 0 || off > output.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            ByteBuffer input = this.input;
+            long result;
+            int inputPos;
+            try {
+                if (input == null) {
+                    inputPos = this.inputPos;
+                    try {
+                        result = inflateBytesBytes(zsRef.address(),
+                            inputArray, inputPos, inputLim - inputPos,
+                            output, off, len);
+                    } catch (DataFormatException e) {
+                        this.inputPos = inputPos + inputConsumed;
+                        throw e;
+                    }
+                } else {
+                    inputPos = input.position();
+                    try {
+                        int inputRem = Math.max(input.limit() - inputPos, 0);
+                        if (input.isDirect()) {
+                            try {
+                                long inputAddress = ((DirectBuffer) input).address();
+                                result = inflateBufferBytes(zsRef.address(),
+                                    inputAddress + inputPos, inputRem,
+                                    output, off, len);
+                            } finally {
+                                Reference.reachabilityFence(input);
+                            }
+                        } else {
+                            byte[] inputArray = ZipUtils.getBufferArray(input);
+                            int inputOffset = ZipUtils.getBufferOffset(input);
+                            result = inflateBytesBytes(zsRef.address(),
+                                inputArray, inputOffset + inputPos, inputRem,
+                                output, off, len);
+                        }
+                    } catch (DataFormatException e) {
+                        input.position(inputPos + inputConsumed);
+                        throw e;
+                    }
+                }
+            } catch (DataFormatException e) {
+                bytesRead += inputConsumed;
+                inputConsumed = 0;
+                int written = outputConsumed;
+                bytesWritten += written;
+                outputConsumed = 0;
+                throw e;
+            }
+            int read = (int) (result & 0x7fff_ffffL);
+            int written = (int) (result >>> 31 & 0x7fff_ffffL);
+            if ((result >>> 62 & 1) != 0) {
+                finished = true;
+            }
+            if ((result >>> 63 & 1) != 0) {
+                needDict = true;
+            }
+            if (input != null) {
+                input.position(inputPos + read);
+            } else {
+                this.inputPos = inputPos + read;
+            }
+            bytesWritten += written;
+            bytesRead += read;
+            return written;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * <p>
+     * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+     * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
+     * method was called to provide a buffer for input, the input buffer's position
+     * will be advanced the number of consumed bytes.
+     * <p>
+     * These byte totals, as well as
+     * the {@linkplain #getBytesRead() total bytes read}
+     * and the {@linkplain #getBytesWritten() total bytes written}
+     * values, will be updated even in the event that a {@link DataFormatException}
+     * is thrown to reflect the amount of data consumed and produced before the
+     * exception occurred.
+     *
+     * @param output the buffer for the uncompressed data
+     * @return the actual number of uncompressed bytes
+     * @throws DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] output) throws DataFormatException {
+        return inflate(output, 0, output.length);
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * <p>
+     * On success, the position of the given {@code output} byte buffer will be
+     * advanced by as many bytes as were produced by the operation, which is equal
+     * to the number returned by this method.  Note that the position of the
+     * {@code output} buffer will be advanced even in the event that a
+     * {@link DataFormatException} is thrown.
+     * <p>
+     * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+     * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
+     * method was called to provide a buffer for input, the input buffer's position
+     * will be advanced the number of consumed bytes.
+     * <p>
+     * These byte totals, as well as
+     * the {@linkplain #getBytesRead() total bytes read}
+     * and the {@linkplain #getBytesWritten() total bytes written}
+     * values, will be updated even in the event that a {@link DataFormatException}
+     * is thrown to reflect the amount of data consumed and produced before the
+     * exception occurred.
+     *
+     * @param output the buffer for the uncompressed data
+     * @return the actual number of uncompressed bytes
+     * @throws DataFormatException if the compressed data format is invalid
+     * @throws ReadOnlyBufferException if the given output buffer is read-only
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     * @since 11
+     */
+    public int inflate(ByteBuffer output) throws DataFormatException {
+        if (output.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            ByteBuffer input = this.input;
+            long result;
+            int inputPos;
+            int outputPos = output.position();
+            int outputRem = Math.max(output.limit() - outputPos, 0);
+            try {
+                if (input == null) {
+                    inputPos = this.inputPos;
+                    try {
+                        if (output.isDirect()) {
+                            long outputAddress = ((DirectBuffer) output).address();
+                            try {
+                                result = inflateBytesBuffer(zsRef.address(),
+                                    inputArray, inputPos, inputLim - inputPos,
+                                    outputAddress + outputPos, outputRem);
+                            } finally {
+                                Reference.reachabilityFence(output);
+                            }
+                        } else {
+                            byte[] outputArray = ZipUtils.getBufferArray(output);
+                            int outputOffset = ZipUtils.getBufferOffset(output);
+                            result = inflateBytesBytes(zsRef.address(),
+                                inputArray, inputPos, inputLim - inputPos,
+                                outputArray, outputOffset + outputPos, outputRem);
+                        }
+                    } catch (DataFormatException e) {
+                        this.inputPos = inputPos + inputConsumed;
+                        throw e;
+                    }
+                } else {
+                    inputPos = input.position();
+                    int inputRem = Math.max(input.limit() - inputPos, 0);
+                    try {
+                        if (input.isDirect()) {
+                            long inputAddress = ((DirectBuffer) input).address();
+                            try {
+                                if (output.isDirect()) {
+                                    long outputAddress = ((DirectBuffer) output).address();
+                                    try {
+                                        result = inflateBufferBuffer(zsRef.address(),
+                                            inputAddress + inputPos, inputRem,
+                                            outputAddress + outputPos, outputRem);
+                                    } finally {
+                                        Reference.reachabilityFence(output);
+                                    }
+                                } else {
+                                    byte[] outputArray = ZipUtils.getBufferArray(output);
+                                    int outputOffset = ZipUtils.getBufferOffset(output);
+                                    result = inflateBufferBytes(zsRef.address(),
+                                        inputAddress + inputPos, inputRem,
+                                        outputArray, outputOffset + outputPos, outputRem);
+                                }
+                            } finally {
+                                Reference.reachabilityFence(input);
+                            }
+                        } else {
+                            byte[] inputArray = ZipUtils.getBufferArray(input);
+                            int inputOffset = ZipUtils.getBufferOffset(input);
+                            if (output.isDirect()) {
+                                long outputAddress = ((DirectBuffer) output).address();
+                                try {
+                                    result = inflateBytesBuffer(zsRef.address(),
+                                        inputArray, inputOffset + inputPos, inputRem,
+                                        outputAddress + outputPos, outputRem);
+                                } finally {
+                                    Reference.reachabilityFence(output);
+                                }
+                            } else {
+                                byte[] outputArray = ZipUtils.getBufferArray(output);
+                                int outputOffset = ZipUtils.getBufferOffset(output);
+                                result = inflateBytesBytes(zsRef.address(),
+                                    inputArray, inputOffset + inputPos, inputRem,
+                                    outputArray, outputOffset + outputPos, outputRem);
+                            }
+                        }
+                    } catch (DataFormatException e) {
+                        input.position(inputPos + inputConsumed);
+                        throw e;
+                    }
+                }
+            } catch (DataFormatException e) {
+                bytesRead += inputConsumed;
+                inputConsumed = 0;
+                int written = outputConsumed;
+                output.position(outputPos + written);
+                bytesWritten += written;
+                outputConsumed = 0;
+                throw e;
+            }
+            int read = (int) (result & 0x7fff_ffffL);
+            int written = (int) (result >>> 31 & 0x7fff_ffffL);
+            if ((result >>> 62 & 1) != 0) {
+                finished = true;
+            }
+            if ((result >>> 63 & 1) != 0) {
+                needDict = true;
+            }
+            if (input != null) {
+                input.position(inputPos + read);
+            } else {
+                this.inputPos = inputPos + read;
+            }
+            // Note: this method call also serves to keep the byteBuffer ref alive
+            output.position(outputPos + written);
+            bytesWritten += written;
+            bytesRead += read;
+            return written;
+        }
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * @return the total (non-negative) number of compressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets inflater so that a new set of input data can be processed.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            // Android-added: CloseGuard support.
+            guard.close();
+            input = ZipUtils.defaultBuf;
+            inputArray = null;
+            finished = false;
+            needDict = false;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the decompressor and discards any unprocessed input.
+     *
+     * This method should be called when the decompressor is no longer
+     * being used. Once this method is called, the behavior of the
+     * Inflater object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            zsRef.clean();
+            // Android-added: CloseGuard support.
+            guard.close();
+            input = ZipUtils.defaultBuf;
+            inputArray = null;
+        }
+    }
+
+
+    private void ensureOpen () {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Inflater has been closed");
+    }
+
+    // Android-changed: initIDs handled in register method.
+    // private native static void initIDs();
+    private static native long init(boolean nowrap);
+    private static native void setDictionary(long addr, byte[] b, int off,
+                                             int len);
+    private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+    private native long inflateBytesBytes(long addr,
+        byte[] inputArray, int inputOff, int inputLen,
+        byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+    private native long inflateBytesBuffer(long addr,
+        byte[] inputArray, int inputOff, int inputLen,
+        long outputAddress, int outputLen) throws DataFormatException;
+    private native long inflateBufferBytes(long addr,
+        long inputAddress, int inputLen,
+        byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+    private native long inflateBufferBuffer(long addr,
+        long inputAddress, int inputLen,
+        long outputAddress, int outputLen) throws DataFormatException;
+    private static native int getAdler(long addr);
+    private static native void reset(long addr);
+    private static native void end(long addr);
+
+    /**
+     * A reference to the native zlib's z_stream structure. It also
+     * serves as the "cleaner" to clean up the native resource when
+     * the Inflater is ended, closed or cleaned.
+     */
+    static class InflaterZStreamRef implements Runnable {
+
+        private long address;
+        private final Cleanable cleanable;
+
+        private InflaterZStreamRef(Inflater owner, long addr) {
+            this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
+            this.address = addr;
+        }
+
+        long address() {
+            return address;
+        }
+
+        void clean() {
+            cleanable.clean();
+        }
+
+        public synchronized void run() {
+            long addr = address;
+            address = 0;
+            if (addr != 0) {
+                end(addr);
+            }
+        }
+
+    }
+}
diff --git a/android-35/java/util/zip/InflaterInputStream.java b/android-35/java/util/zip/InflaterInputStream.java
new file mode 100644
index 0000000..0eb85ad
--- /dev/null
+++ b/android-35/java/util/zip/InflaterInputStream.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for uncompressing data in the
+ * "deflate" compression format. It is also used as the basis for other
+ * decompression filters, such as GZIPInputStream.
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class InflaterInputStream extends FilterInputStream {
+    /**
+     * Decompressor for this stream.
+     */
+    protected Inflater inf;
+
+    /**
+     * Input buffer for decompression.
+     */
+    protected byte[] buf;
+
+    /**
+     * Length of input buffer.
+     */
+    protected int len;
+
+    // Android-changed: Make closed accessible to subclasses.
+    // This was made protected because it needed to be accessed by
+    // StrictJarFile.ZipInflaterInputStream. Unfortunately, it was not marked as @hide and so it
+    // inadvertently became part of the public API. It will be marked as @removed to remove it from
+    // the public API in a future release of Android. See http://b/111592689 for more information.
+    // private boolean closed = false;
+    /**
+     * Indicates whether the {@link #close()} method has been called, internal use only.
+     *
+     * @deprecated This field will be removed from a future version of Android and should not be
+     * used. Subclasses that access this field need to be modified to keep track of their own
+     * closed state by overriding close().
+     */
+    @Deprecated
+    protected boolean closed = false;
+
+    // this flag is set to true after EOF has reached
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    // Android-added: constructor which explicitly sets whether Inflater is owned by this stream.
+    /**
+     * Creates a new input stream with the specified decompressor and
+     * buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     * @param size the input buffer size
+     * @param ownsInflater whether this {@code InflaterInputStream} controls its inflater
+     *                     lifetime and should call {@link Inflater#end} when it is closed.
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     * @hide
+     */
+    InflaterInputStream(InputStream in, Inflater inf, int size, boolean ownsInflater) {
+        super(in);
+        if (in == null || inf == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.inf = inf;
+        buf = new byte[size];
+        this.ownsInflater = ownsInflater;
+    }
+
+    /**
+     * Creates a new input stream with the specified decompressor and
+     * buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     * @param size the input buffer size
+     * @throws    IllegalArgumentException if {@code size <= 0}
+     */
+    public InflaterInputStream(InputStream in, Inflater inf, int size) {
+        // Android-changed: refer initialization to constructor which specifies ownInflater.
+        /*
+        super(in);
+        if (in == null || inf == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.inf = inf;
+        buf = new byte[size];
+        */
+        this(in, inf, size, /* ownsInflater= */ true);
+    }
+
+    /**
+     * Creates a new input stream with the specified decompressor and a
+     * default buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     */
+    public InflaterInputStream(InputStream in, Inflater inf) {
+        this(in, inf, 512);
+    }
+
+    // Android-changed: Unconditionally close external inflaters (b/26462400)
+    // See http://b/111630946 for more details.
+    // boolean usesDefaultInflater = false;
+
+    // Android-added: functionally this is identical to usesDefaultInflater, but re-using
+    // it will be confusing. Setting it to true keeps old Android behaviour.
+    // This is added just for ZipFileInflaterInputStream - moving to usesDefaultInflater
+    // is trickier.
+    private final boolean ownsInflater;
+
+    /**
+     * Creates a new input stream with a default decompressor and buffer size.
+     * @param in the input stream
+     */
+    public InflaterInputStream(InputStream in) {
+        this(in, in != null ? new Inflater() : null);
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+    }
+
+    private byte[] singleByteBuf = new byte[1];
+
+    /**
+     * Reads a byte of uncompressed data. This method will block until
+     * enough input is available for decompression.
+     * @return the byte read, or -1 if end of compressed input is reached
+     * @throws    IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        ensureOpen();
+        return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If {@code len} is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and {@code 0} is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array {@code b}
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         compressed input is reached or a preset dictionary is needed
+     * @throws     NullPointerException If {@code b} is {@code null}.
+     * @throws     IndexOutOfBoundsException If {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code b.length - off}
+     * @throws    ZipException if a ZIP format error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        try {
+            int n;
+            while ((n = inf.inflate(b, off, len)) == 0) {
+                if (inf.finished() || inf.needsDictionary()) {
+                    reachEOF = true;
+                    return -1;
+                }
+                if (inf.needsInput()) {
+                    fill();
+                }
+            }
+            return n;
+        } catch (DataFormatException e) {
+            String s = e.getMessage();
+            throw new ZipException(s != null ? s : "Invalid ZLIB data format");
+        }
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF.
+     * @throws     IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        } else if (inf.finished()) {
+            // the end of the compressed data stream has been reached
+            reachEOF = true;
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    private byte[] b = new byte[512];
+
+    /**
+     * Skips specified number of bytes of uncompressed data.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped.
+     * @throws    IOException if an I/O error has occurred
+     * @throws    IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > b.length) {
+                len = b.length;
+            }
+            len = read(b, 0, len);
+            if (len == -1) {
+                reachEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // BEGIN Android-changed: close inflater only if it is owned by this
+            // InflaterInputStream. (b/26462400)
+            /*
+            if (usesDefaultInflater)
+                inf.end();
+            */
+            if (ownsInflater) {
+                inf.end();
+            }
+            // END Android-changed: close inflater only if it is owned by this
+            // InflaterInputStream. (b/26462400)
+            in.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Fills input buffer with more data to decompress.
+     * @throws    IOException if an I/O error has occurred
+     */
+    protected void fill() throws IOException {
+        ensureOpen();
+        len = in.read(buf, 0, buf.length);
+        if (len == -1) {
+            throw new EOFException("Unexpected end of ZLIB input stream");
+        }
+        inf.setInput(buf, 0, len);
+    }
+
+    /**
+     * Tests if this input stream supports the {@code mark} and
+     * {@code reset} methods. The {@code markSupported}
+     * method of {@code InflaterInputStream} returns
+     * {@code false}.
+     *
+     * @return  a {@code boolean} indicating if this stream type supports
+     *          the {@code mark} and {@code reset} methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Marks the current position in this input stream.
+     *
+     * <p> The {@code mark} method of {@code InflaterInputStream}
+     * does nothing.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.InputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * {@code mark} method was last called on this input stream.
+     *
+     * <p> The method {@code reset} for class
+     * {@code InflaterInputStream} does nothing except throw an
+     * {@code IOException}.
+     *
+     * @throws     IOException  if this method is invoked.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.IOException
+     */
+    public synchronized void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/android-35/java/util/zip/InflaterOutputStream.java b/android-35/java/util/zip/InflaterOutputStream.java
new file mode 100644
index 0000000..aa30623
--- /dev/null
+++ b/android-35/java/util/zip/InflaterOutputStream.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Implements an output stream filter for uncompressing data stored in the
+ * "deflate" compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see InflaterInputStream
+ * @see DeflaterInputStream
+ * @see DeflaterOutputStream
+ */
+
+public class InflaterOutputStream extends FilterOutputStream {
+    /** Decompressor for this stream. */
+    protected final Inflater inf;
+
+    /** Output buffer for writing uncompressed data. */
+    protected final byte[] buf;
+
+    /** Temporary write buffer. */
+    private final byte[] wbuf = new byte[1];
+
+    /** Default decompressor is used. */
+    private boolean usesDefaultInflater = false;
+
+    /** true iff {@link #close()} has been called. */
+    private boolean closed = false;
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new output stream with a default decompressor and buffer
+     * size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @throws NullPointerException if {@code out} is null
+     */
+    public InflaterOutputStream(OutputStream out) {
+        this(out, out != null ? new Inflater() : null);
+        usesDefaultInflater = true;
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and a
+     * default buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl) {
+        this(out, infl, 512);
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and
+     * buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @param bufLen decompression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) {
+        super(out);
+
+        // Sanity checks
+        if (out == null)
+            throw new NullPointerException("Null output");
+        if (infl == null)
+            throw new NullPointerException("Null inflater");
+        if (bufLen <= 0)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        inf = infl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Writes any remaining uncompressed data to the output stream and closes
+     * the underlying output stream.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // Complete the uncompressed output
+            try {
+                finish();
+            } finally {
+                out.close();
+                closed = true;
+            }
+        }
+    }
+
+    /**
+     * Flushes this output stream, forcing any pending buffered output bytes to be
+     * written.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void flush() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        if (!inf.finished()) {
+            try {
+                while (!inf.finished()  &&  !inf.needsInput()) {
+                    int n;
+
+                    // Decompress pending output data
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n < 1) {
+                        break;
+                    }
+
+                    // Write the uncompressed output data block
+                    out.write(buf, 0, n);
+                }
+                super.flush();
+            } catch (DataFormatException ex) {
+                // Improperly formatted compressed (ZIP) data
+                String msg = ex.getMessage();
+                if (msg == null) {
+                    msg = "Invalid ZLIB data format";
+                }
+                throw new ZipException(msg);
+            }
+        }
+    }
+
+    /**
+     * Finishes writing uncompressed data to the output stream without closing
+     * the underlying stream.  Use this method when applying multiple filters in
+     * succession to the same output stream.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        flush();
+        if (usesDefaultInflater) {
+            inf.end();
+        }
+    }
+
+    /**
+     * Writes a byte to the uncompressed output stream.
+     *
+     * @param b a single byte of compressed data to decompress and write to
+     * the output stream
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(int b) throws IOException {
+        // Write a single byte of data
+        wbuf[0] = (byte) b;
+        write(wbuf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the uncompressed output stream.
+     *
+     * @param b buffer containing compressed data to decompress and write to
+     * the output stream
+     * @param off starting offset of the compressed data within {@code b}
+     * @param len number of bytes to decompress from {@code b}
+     * @throws IndexOutOfBoundsException if {@code off < 0}, or if
+     * {@code len < 0}, or if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws NullPointerException if {@code b} is null
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        // Write uncompressed data to the output stream
+        try {
+            for (;;) {
+                int n;
+
+                // Fill the decompressor buffer with output data
+                if (inf.needsInput()) {
+                    inf.setInput(b, off, len);
+                    // Only use input buffer once.
+                    len = 0;
+                }
+
+                // Decompress and write blocks of output data
+                do {
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n > 0) {
+                        out.write(buf, 0, n);
+                    }
+                } while (n > 0);
+
+                // Check for missing dictionary first
+                if (inf.needsDictionary()) {
+                    throw new ZipException("ZLIB dictionary missing");
+                }
+                // Check the decompressor
+                if (inf.finished() || (len == 0)/* no more input */) {
+                    break;
+                }
+            }
+        } catch (DataFormatException ex) {
+            // Improperly formatted compressed (ZIP) data
+            String msg = ex.getMessage();
+            if (msg == null) {
+                msg = "Invalid ZLIB data format";
+            }
+            throw new ZipException(msg);
+        }
+    }
+}
diff --git a/android-35/java/util/zip/ZipCoder.java b/android-35/java/util/zip/ZipCoder.java
new file mode 100644
index 0000000..450d7a6
--- /dev/null
+++ b/android-35/java/util/zip/ZipCoder.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * Utility class for zipfile name and comment decoding and encoding
+ */
+class ZipCoder {
+
+    // Android-removed:
+    // private static final jdk.internal.access.JavaLangAccess JLA =
+    //    jdk.internal.access.SharedSecrets.getJavaLangAccess();
+
+    // Encoding/decoding is stateless, so make it singleton.
+    // Android-changed: use StandardCharsets.
+    // static final UTF8ZipCoder UTF8 = new UTF8ZipCoder(UTF_8.INSTANCE);
+    static final UTF8ZipCoder UTF8 = new UTF8ZipCoder(StandardCharsets.UTF_8);
+
+    public static ZipCoder get(Charset charset) {
+        // Android-changed: use equals method, not reference comparison.
+        // if (charset == UTF_8.INSTANCE) {
+        if (StandardCharsets.UTF_8.equals(charset)) {
+            return UTF8;
+        }
+        return new ZipCoder(charset);
+    }
+
+    String toString(byte[] ba, int off, int length) {
+        try {
+            return decoder().decode(ByteBuffer.wrap(ba, off, length)).toString();
+        } catch (CharacterCodingException x) {
+            throw new IllegalArgumentException(x);
+        }
+    }
+
+    String toString(byte[] ba, int length) {
+        return toString(ba, 0, length);
+    }
+
+    String toString(byte[] ba) {
+        return toString(ba, 0, ba.length);
+    }
+
+    byte[] getBytes(String s) {
+        try {
+            ByteBuffer bb = encoder().encode(CharBuffer.wrap(s));
+            int pos = bb.position();
+            int limit = bb.limit();
+            if (bb.hasArray() && pos == 0 && limit == bb.capacity()) {
+                return bb.array();
+            }
+            byte[] bytes = new byte[bb.limit() - bb.position()];
+            bb.get(bytes);
+            return bytes;
+        } catch (CharacterCodingException x) {
+            throw new IllegalArgumentException(x);
+        }
+    }
+
+    static String toStringUTF8(byte[] ba, int len) {
+        return UTF8.toString(ba, 0, len);
+    }
+
+    boolean isUTF8() {
+        return false;
+    }
+
+    // Hash code functions for ZipFile entry names. We generate the hash as-if
+    // we first decoded the byte sequence to a String, then appended '/' if no
+    // trailing slash was found, then called String.hashCode(). This
+    // normalization ensures we can simplify and speed up lookups.
+    //
+    // Does encoding error checking and hashing in a single pass for efficiency.
+    // On an error, this function will throw CharacterCodingException while the
+    // UTF8ZipCoder override will throw IllegalArgumentException, so we declare
+    // throws Exception to keep things simple.
+    int checkedHash(byte[] a, int off, int len) throws Exception {
+        if (len == 0) {
+            return 0;
+        }
+
+        int h = 0;
+        // cb will be a newly allocated CharBuffer with pos == 0,
+        // arrayOffset == 0, backed by an array.
+        CharBuffer cb = decoder().decode(ByteBuffer.wrap(a, off, len));
+        int limit = cb.limit();
+        char[] decoded = cb.array();
+        for (int i = 0; i < limit; i++) {
+            h = 31 * h + decoded[i];
+        }
+        if (limit > 0 && decoded[limit - 1] != '/') {
+            h = 31 * h + '/';
+        }
+        return h;
+    }
+
+    // Hash function equivalent of checkedHash for String inputs
+    static int hash(String name) {
+        int hsh = name.hashCode();
+        int len = name.length();
+        if (len > 0 && name.charAt(len - 1) != '/') {
+            hsh = hsh * 31 + '/';
+        }
+        return hsh;
+    }
+
+    boolean hasTrailingSlash(byte[] a, int end) {
+        byte[] slashBytes = slashBytes();
+        return end >= slashBytes.length &&
+            Arrays.mismatch(a, end - slashBytes.length, end, slashBytes, 0, slashBytes.length) == -1;
+    }
+
+    private byte[] slashBytes;
+    private final Charset cs;
+    protected CharsetDecoder dec;
+    private CharsetEncoder enc;
+
+    private ZipCoder(Charset cs) {
+        this.cs = cs;
+    }
+
+    protected CharsetDecoder decoder() {
+        if (dec == null) {
+            dec = cs.newDecoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return dec;
+    }
+
+    private CharsetEncoder encoder() {
+        if (enc == null) {
+            enc = cs.newEncoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return enc;
+    }
+
+    // This method produces an array with the bytes that will correspond to a
+    // trailing '/' in the chosen character encoding.
+    //
+    // While in most charsets a trailing slash will be encoded as the byte
+    // value of '/', this does not hold in the general case. E.g., in charsets
+    // such as UTF-16 and UTF-32 it will be represented by a sequence of 2 or 4
+    // bytes, respectively.
+    private byte[] slashBytes() {
+        if (slashBytes == null) {
+            // Take into account charsets that produce a BOM, e.g., UTF-16
+            byte[] slash = "/".getBytes(cs);
+            byte[] doubleSlash = "//".getBytes(cs);
+            slashBytes = Arrays.copyOfRange(doubleSlash, slash.length, doubleSlash.length);
+        }
+        return slashBytes;
+    }
+
+    static final class UTF8ZipCoder extends ZipCoder {
+
+        private UTF8ZipCoder(Charset utf8) {
+            super(utf8);
+        }
+
+        @Override
+        boolean isUTF8() {
+            return true;
+        }
+
+        @Override
+        String toString(byte[] ba, int off, int length) {
+            // Android-changed: JLA is not yet available.
+            // return JLA.newStringUTF8NoRepl(ba, off, length);
+            return new String(ba, off, length, StandardCharsets.UTF_8);
+        }
+
+        @Override
+        byte[] getBytes(String s) {
+            // Android-changed: JLA is not yet available.
+            // return JLA.getBytesUTF8NoRepl(s);
+            return s.getBytes(StandardCharsets.UTF_8);
+        }
+
+        @Override
+        int checkedHash(byte[] a, int off, int len) throws Exception {
+            if (len == 0) {
+                return 0;
+            }
+
+            int end = off + len;
+            int h = 0;
+            while (off < end) {
+                byte b = a[off];
+                if (b >= 0) {
+                    // ASCII, keep going
+                    h = 31 * h + b;
+                    off++;
+                } else {
+                    // Non-ASCII, fall back to decoding a String
+                    // We avoid using decoder() here since the UTF8ZipCoder is
+                    // shared and that decoder is not thread safe.
+                    // We use the JLA.newStringUTF8NoRepl variant to throw
+                    // exceptions eagerly when opening ZipFiles
+                    // Android-changed: JLA is not yet available.
+                    // return hash(JLA.newStringUTF8NoRepl(a, end - len, len));
+                    return hash(new String(a, end - len, len, StandardCharsets.UTF_8));
+                }
+            }
+
+            if (a[end - 1] != '/') {
+                h = 31 * h + '/';
+            }
+            return h;
+        }
+
+        @Override
+        boolean hasTrailingSlash(byte[] a, int end) {
+            return end > 0 && a[end - 1] == '/';
+        }
+    }
+}
diff --git a/android-35/java/util/zip/ZipConstants.java b/android-35/java/util/zip/ZipConstants.java
new file mode 100644
index 0000000..9eac888
--- /dev/null
+++ b/android-35/java/util/zip/ZipConstants.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This interface defines the constants that are used by the classes
+ * which manipulate ZIP files.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+interface ZipConstants {
+
+    /**
+     * Local file (LOC) header signature.
+     */
+    static long LOCSIG = 0x04034b50L;   // "PK\003\004"
+
+    /**
+     * Extra local (EXT) header signature.
+     */
+    static long EXTSIG = 0x08074b50L;   // "PK\007\008"
+
+    /**
+     * Central directory (CEN) header signature.
+     */
+    static long CENSIG = 0x02014b50L;   // "PK\001\002"
+
+    /**
+     * End of central directory (END) header signature.
+     */
+    static long ENDSIG = 0x06054b50L;   // "PK\005\006"
+
+    /**
+     * Local file (LOC) header size in bytes (including signature).
+     */
+    static final int LOCHDR = 30;
+
+    /**
+     * Extra local (EXT) header size in bytes (including signature).
+     */
+    static final int EXTHDR = 16;
+
+    /**
+     * Central directory (CEN) header size in bytes (including signature).
+     */
+    static final int CENHDR = 46;
+
+    /**
+     * End of central directory (END) header size in bytes (including signature).
+     */
+    static final int ENDHDR = 22;
+
+    /**
+     * Local file (LOC) header version needed to extract field offset.
+     */
+    static final int LOCVER = 4;
+
+    /**
+     * Local file (LOC) header general purpose bit flag field offset.
+     */
+    static final int LOCFLG = 6;
+
+    /**
+     * Local file (LOC) header compression method field offset.
+     */
+    static final int LOCHOW = 8;
+
+    /**
+     * Local file (LOC) header modification time field offset.
+     */
+    static final int LOCTIM = 10;
+
+    /**
+     * Local file (LOC) header uncompressed file crc-32 value field offset.
+     */
+    static final int LOCCRC = 14;
+
+    /**
+     * Local file (LOC) header compressed size field offset.
+     */
+    static final int LOCSIZ = 18;
+
+    /**
+     * Local file (LOC) header uncompressed size field offset.
+     */
+    static final int LOCLEN = 22;
+
+    /**
+     * Local file (LOC) header filename length field offset.
+     */
+    static final int LOCNAM = 26;
+
+    /**
+     * Local file (LOC) header extra field length field offset.
+     */
+    static final int LOCEXT = 28;
+
+    /**
+     * Extra local (EXT) header uncompressed file crc-32 value field offset.
+     */
+    static final int EXTCRC = 4;
+
+    /**
+     * Extra local (EXT) header compressed size field offset.
+     */
+    static final int EXTSIZ = 8;
+
+    /**
+     * Extra local (EXT) header uncompressed size field offset.
+     */
+    static final int EXTLEN = 12;
+
+    /**
+     * Central directory (CEN) header version made by field offset.
+     */
+    static final int CENVEM = 4;
+
+    /**
+     * Central directory (CEN) header version needed to extract field offset.
+     */
+    static final int CENVER = 6;
+
+    /**
+     * Central directory (CEN) header encrypt, decrypt flags field offset.
+     */
+    static final int CENFLG = 8;
+
+    /**
+     * Central directory (CEN) header compression method field offset.
+     */
+    static final int CENHOW = 10;
+
+    /**
+     * Central directory (CEN) header modification time field offset.
+     */
+    static final int CENTIM = 12;
+
+    /**
+     * Central directory (CEN) header uncompressed file crc-32 value field offset.
+     */
+    static final int CENCRC = 16;
+
+    /**
+     * Central directory (CEN) header compressed size field offset.
+     */
+    static final int CENSIZ = 20;
+
+    /**
+     * Central directory (CEN) header uncompressed size field offset.
+     */
+    static final int CENLEN = 24;
+
+    /**
+     * Central directory (CEN) header filename length field offset.
+     */
+    static final int CENNAM = 28;
+
+    /**
+     * Central directory (CEN) header extra field length field offset.
+     */
+    static final int CENEXT = 30;
+
+    /**
+     * Central directory (CEN) header comment length field offset.
+     */
+    static final int CENCOM = 32;
+
+    /**
+     * Central directory (CEN) header disk number start field offset.
+     */
+    static final int CENDSK = 34;
+
+    /**
+     * Central directory (CEN) header internal file attributes field offset.
+     */
+    static final int CENATT = 36;
+
+    /**
+     * Central directory (CEN) header external file attributes field offset.
+     */
+    static final int CENATX = 38;
+
+    /**
+     * Central directory (CEN) header LOC header offset field offset.
+     */
+    static final int CENOFF = 42;
+
+    /**
+     * End of central directory (END) header number of entries on this disk field offset.
+     */
+    static final int ENDSUB = 8;
+
+    /**
+     * End of central directory (END) header total number of entries field offset.
+     */
+    static final int ENDTOT = 10;
+
+    /**
+     * End of central directory (END) header central directory size in bytes field offset.
+     */
+    static final int ENDSIZ = 12;
+
+    /**
+     * End of central directory (END) header offset for the first CEN header field offset.
+     */
+    static final int ENDOFF = 16;
+
+    /**
+     * End of central directory (END) header zip file comment length field offset.
+     */
+    static final int ENDCOM = 20;
+}
diff --git a/android-35/java/util/zip/ZipConstants64.java b/android-35/java/util/zip/ZipConstants64.java
new file mode 100644
index 0000000..d78eaf4
--- /dev/null
+++ b/android-35/java/util/zip/ZipConstants64.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This class defines the constants that are used by the classes
+ * which manipulate Zip64 files.
+ */
+
+class ZipConstants64 {
+
+    /*
+     * ZIP64 constants
+     */
+    static final long ZIP64_ENDSIG = 0x06064b50L;  // "PK\006\006"
+    static final long ZIP64_LOCSIG = 0x07064b50L;  // "PK\006\007"
+    static final int  ZIP64_ENDHDR = 56;           // ZIP64 end header size
+    static final int  ZIP64_LOCHDR = 20;           // ZIP64 end loc header size
+    static final int  ZIP64_EXTHDR = 24;           // EXT header size
+    static final int  ZIP64_EXTID  = 0x0001;       // Extra field Zip64 header ID
+
+    static final int  ZIP64_MAGICCOUNT = 0xFFFF;
+    static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
+
+    /*
+     * Zip64 End of central directory (END) header field offsets
+     */
+    static final int  ZIP64_ENDLEN = 4;       // size of zip64 end of central dir
+    static final int  ZIP64_ENDVEM = 12;      // version made by
+    static final int  ZIP64_ENDVER = 14;      // version needed to extract
+    static final int  ZIP64_ENDNMD = 16;      // number of this disk
+    static final int  ZIP64_ENDDSK = 20;      // disk number of start
+    static final int  ZIP64_ENDTOD = 24;      // total number of entries on this disk
+    static final int  ZIP64_ENDTOT = 32;      // total number of entries
+    static final int  ZIP64_ENDSIZ = 40;      // central directory size in bytes
+    static final int  ZIP64_ENDOFF = 48;      // offset of first CEN header
+    static final int  ZIP64_ENDEXT = 56;      // zip64 extensible data sector
+
+    /*
+     * Zip64 End of central directory locator field offsets
+     */
+    static final int  ZIP64_LOCDSK = 4;       // disk number start
+    static final int  ZIP64_LOCOFF = 8;       // offset of zip64 end
+    static final int  ZIP64_LOCTOT = 16;      // total number of disks
+
+    /*
+     * Zip64 Extra local (EXT) header field offsets
+     */
+    static final int  ZIP64_EXTCRC = 4;       // uncompressed file crc-32 value
+    static final int  ZIP64_EXTSIZ = 8;       // compressed size, 8-byte
+    static final int  ZIP64_EXTLEN = 16;      // uncompressed size, 8-byte
+
+    /*
+     * Language encoding flag (general purpose flag bit 11)
+     *
+     * If this bit is set the filename and comment fields for this
+     * entry must be encoded using UTF-8.
+     */
+    static final int USE_UTF8 = 0x800;
+
+    /*
+     * Constants below are defined here (instead of in ZipConstants)
+     * to avoid being exposed as public fields of ZipFile, ZipEntry,
+     * ZipInputStream and ZipOutputstream.
+     */
+
+    /*
+     * Extra field header ID
+     */
+    static final int  EXTID_ZIP64 = 0x0001;    // Zip64
+    static final int  EXTID_NTFS  = 0x000a;    // NTFS
+    static final int  EXTID_UNIX  = 0x000d;    // UNIX
+    static final int  EXTID_EXTT  = 0x5455;    // Info-ZIP Extended Timestamp
+
+    /*
+     * EXTT timestamp flags
+     */
+    static final int  EXTT_FLAG_LMT = 0x1;       // LastModifiedTime
+    static final int  EXTT_FLAG_LAT = 0x2;       // LastAccessTime
+    static final int  EXTT_FLAT_CT  = 0x4;       // CreationTime
+
+    private ZipConstants64() {}
+}
diff --git a/android-35/java/util/zip/ZipEntry.java b/android-35/java/util/zip/ZipEntry.java
new file mode 100644
index 0000000..3d1d522
--- /dev/null
+++ b/android-35/java/util/zip/ZipEntry.java
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import static java.util.zip.ZipUtils.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.FileTime;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
+
+import static java.util.zip.ZipConstants64.*;
+
+/**
+ * This class is used to represent a ZIP file entry.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class ZipEntry implements ZipConstants, Cloneable {
+
+    String name;        // entry name
+    long xdostime = -1; // last modification time (in extended DOS time,
+                        // where milliseconds lost in conversion might
+                        // be encoded into the upper half)
+    FileTime mtime;     // last modification time, from extra field data
+    FileTime atime;     // last access time, from extra field data
+    FileTime ctime;     // creation time, from extra field data
+    long crc = -1;      // crc-32 of entry data
+    long size = -1;     // uncompressed size of entry data
+    long csize = -1;    // compressed size of entry data
+    boolean csizeSet = false; // Only true if csize was explicitely set by
+                        // a call to setCompressedSize()
+    int method = -1;    // compression method
+    int flag = 0;       // general purpose flag
+    byte[] extra;       // optional extra field data for entry
+    String comment;     // optional comment string for entry
+    int extraAttributes = -1; // e.g. POSIX permissions, sym links.
+    // Android-added: Add dataOffset for internal use.
+    // Used by android.util.jar.StrictJarFile from frameworks.
+    long dataOffset;
+
+    /**
+     * Compression method for uncompressed entries.
+     */
+    public static final int STORED = 0;
+
+    /**
+     * Compression method for compressed (deflated) entries.
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * DOS time constant for representing timestamps before 1980.
+     */
+    static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
+
+    /**
+     * Approximately 128 years, in milliseconds (ignoring leap years etc).
+     *
+     * This establish an approximate high-bound value for DOS times in
+     * milliseconds since epoch, used to enable an efficient but
+     * sufficient bounds check to avoid generating extended last modified
+     * time entries.
+     *
+     * Calculating the exact number is locale dependent, would require loading
+     * TimeZone data eagerly, and would make little practical sense. Since DOS
+     * times theoretically go to 2107 - with compatibility not guaranteed
+     * after 2099 - setting this to a time that is before but near 2099
+     * should be sufficient.
+     * @hide
+     */
+    // Android-changed: Make UPPER_DOSTIME_BOUND public hidden for testing purposes.
+    public static final long UPPER_DOSTIME_BOUND =
+            128L * 365 * 24 * 60 * 60 * 1000;
+
+    // Android-added: New constructor for use by StrictJarFile native code.
+    /** @hide */
+    public ZipEntry(String name, String comment, long crc, long compressedSize,
+            long size, int compressionMethod, int xdostime, byte[] extra,
+            long dataOffset) {
+        this.name = name;
+        this.comment = comment;
+        this.crc = crc;
+        this.csize = compressedSize;
+        this.size = size;
+        this.method = compressionMethod;
+        this.xdostime = xdostime;
+        this.dataOffset = dataOffset;
+        this.setExtra0(extra, false, false);
+    }
+
+    /**
+     * Creates a new zip entry with the specified name.
+     *
+     * @param  name
+     *         The entry name
+     *
+     * @throws NullPointerException if the entry name is null
+     * @throws IllegalArgumentException if the entry name is longer than
+     *         0xFFFF bytes
+     */
+    public ZipEntry(String name) {
+        Objects.requireNonNull(name, "name");
+        // Android-changed: Explicitly use UTF_8 instead of the default charset.
+        // if (name.length() > 0xFFFF) {
+        //     throw new IllegalArgumentException("entry name too long");
+        // }
+        if (name.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(name + " too long: " +
+                    name.getBytes(StandardCharsets.UTF_8).length);
+        }
+        this.name = name;
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified
+     * zip entry.
+     *
+     * @param  e
+     *         A zip Entry object
+     *
+     * @throws NullPointerException if the entry object is null
+     */
+    public ZipEntry(ZipEntry e) {
+        Objects.requireNonNull(e, "entry");
+        name = e.name;
+        xdostime = e.xdostime;
+        mtime = e.mtime;
+        atime = e.atime;
+        ctime = e.ctime;
+        crc = e.crc;
+        size = e.size;
+        csize = e.csize;
+        csizeSet = e.csizeSet;
+        method = e.method;
+        flag = e.flag;
+        extra = e.extra;
+        comment = e.comment;
+        extraAttributes = e.extraAttributes;
+        // Android-added: Add dataOffset for internal use.
+        dataOffset = e.dataOffset;
+    }
+
+    /**
+     * Creates a new un-initialized zip entry
+     */
+    ZipEntry() {}
+
+    // BEGIN Android-added: Add dataOffset for internal use.
+    /** @hide */
+    public long getDataOffset() {
+        return dataOffset;
+    }
+    // END Android-added: Add dataOffset for internal use.
+
+    /**
+     * Returns the name of the entry.
+     * @return the name of the entry
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> If the entry is output to a ZIP file or ZIP file formatted
+     * output stream the last modification time set by this method will
+     * be stored into the {@code date and time fields} of the zip file
+     * entry and encoded in standard {@code MS-DOS date and time format}.
+     * The {@link java.util.TimeZone#getDefault() default TimeZone} is
+     * used to convert the epoch time to the MS-DOS data and time.
+     *
+     * @param  time
+     *         The last modification time of the entry in milliseconds
+     *         since the epoch
+     *
+     * @see #getTime()
+     * @see #getLastModifiedTime()
+     */
+    public void setTime(long time) {
+        this.xdostime = javaToExtendedDosTime(time);
+        // Avoid setting the mtime field if time is in the valid
+        // range for a DOS time
+        if (this.xdostime != DOSTIME_BEFORE_1980 && time <= UPPER_DOSTIME_BOUND) {
+            this.mtime = null;
+        } else {
+            int localYear = javaEpochToLocalDateTime(time).getYear();
+            if (localYear >= 1980 && localYear <= 2099) {
+                this.mtime = null;
+            } else {
+                this.mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
+            }
+        }
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the {@code
+     * date and time fields} of the zip file entry. The
+     * {@link java.util.TimeZone#getDefault() default TimeZone} is used
+     * to convert the standard MS-DOS formatted date and time to the
+     * epoch time.
+     *
+     * @return  The last modification time of the entry in milliseconds
+     *          since the epoch, or -1 if not specified
+     *
+     * @see #setTime(long)
+     * @see #setLastModifiedTime(FileTime)
+     */
+    public long getTime() {
+        if (mtime != null) {
+            return mtime.toMillis();
+        }
+        return (xdostime != -1) ? extendedDosToJavaTime(xdostime) : -1;
+    }
+
+    /**
+     * Sets the last modification time of the entry in local date-time.
+     *
+     * <p> If the entry is output to a ZIP file or ZIP file formatted
+     * output stream the last modification time set by this method will
+     * be stored into the {@code date and time fields} of the zip file
+     * entry and encoded in standard {@code MS-DOS date and time format}.
+     * If the date-time set is out of the range of the standard {@code
+     * MS-DOS date and time format}, the time will also be stored into
+     * zip file entry's extended timestamp fields in {@code optional
+     * extra data} in UTC time. The {@link java.time.ZoneId#systemDefault()
+     * system default TimeZone} is used to convert the local date-time
+     * to UTC time.
+     *
+     * <p> {@code LocalDateTime} uses a precision of nanoseconds, whereas
+     * this class uses a precision of milliseconds. The conversion will
+     * truncate any excess precision information as though the amount in
+     * nanoseconds was subject to integer division by one million.
+     *
+     * @param  time
+     *         The last modification time of the entry in local date-time
+     *
+     * @see #getTimeLocal()
+     * @since 9
+     */
+    public void setTimeLocal(LocalDateTime time) {
+        int year = time.getYear() - 1980;
+        if (year < 0) {
+            this.xdostime = DOSTIME_BEFORE_1980;
+        } else {
+            this.xdostime = ((year << 25 |
+                time.getMonthValue() << 21 |
+                time.getDayOfMonth() << 16 |
+                time.getHour() << 11 |
+                time.getMinute() << 5 |
+                time.getSecond() >> 1) & 0xffffffffL)
+                + ((long)(((time.getSecond() & 0x1) * 1000) +
+                      time.getNano() / 1000_000) << 32);
+        }
+        if (xdostime != DOSTIME_BEFORE_1980 && year <= 0x7f) {
+            this.mtime = null;
+        } else {
+            this.mtime = FileTime.from(
+                ZonedDateTime.of(time, ZoneId.systemDefault()).toInstant());
+        }
+    }
+
+    /**
+     * Returns the last modification time of the entry in local date-time.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the zip
+     * file entry's {@code optional extra data} if the extended timestamp
+     * fields are present. Otherwise, the last modification time is read
+     * from entry's standard MS-DOS formatted {@code date and time fields}.
+     *
+     * <p> The {@link java.time.ZoneId#systemDefault() system default TimeZone}
+     * is used to convert the UTC time to local date-time.
+     *
+     * @return  The last modification time of the entry in local date-time
+     *
+     * @see #setTimeLocal(LocalDateTime)
+     * @since 9
+     */
+    public LocalDateTime getTimeLocal() {
+        if (mtime != null) {
+            return LocalDateTime.ofInstant(mtime.toInstant(), ZoneId.systemDefault());
+        }
+        int ms = (int)(xdostime >> 32);
+        return LocalDateTime.of((int)(((xdostime >> 25) & 0x7f) + 1980),
+                             (int)((xdostime >> 21) & 0x0f),
+                             (int)((xdostime >> 16) & 0x1f),
+                             (int)((xdostime >> 11) & 0x1f),
+                             (int)((xdostime >> 5) & 0x3f),
+                             (int)((xdostime << 1) & 0x3e) + ms / 1000,
+                             (ms % 1000) * 1000_000);
+    }
+
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> When output to a ZIP file or ZIP file formatted output stream
+     * the last modification time set by this method will be stored into
+     * zip file entry's {@code date and time fields} in {@code standard
+     * MS-DOS date and time format}), and the extended timestamp fields
+     * in {@code optional extra data} in UTC time.
+     *
+     * @param  time
+     *         The last modification time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastModifiedTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastModifiedTime(FileTime time) {
+        this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
+        this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
+        return this;
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the zip
+     * file entry's {@code optional extra data} if the extended timestamp
+     * fields are present. Otherwise the last modification time is read
+     * from the entry's {@code date and time fields}, the {@link
+     * java.util.TimeZone#getDefault() default TimeZone} is used to convert
+     * the standard MS-DOS formatted date and time to the epoch time.
+     *
+     * @return The last modification time of the entry, null if not specified
+     *
+     * @see #setLastModifiedTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastModifiedTime() {
+        if (mtime != null)
+            return mtime;
+        if (xdostime == -1)
+            return null;
+        return FileTime.from(getTime(), TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Sets the last access time of the entry.
+     *
+     * <p> If set, the last access time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when output
+     * to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The last access time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastAccessTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastAccessTime(FileTime time) {
+        this.atime = Objects.requireNonNull(time, "lastAccessTime");
+        return this;
+    }
+
+    /**
+     * Returns the last access time of the entry.
+     *
+     * <p> The last access time is from the extended timestamp fields
+     * of entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return The last access time of the entry, null if not specified
+     * @see #setLastAccessTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastAccessTime() {
+        return atime;
+    }
+
+    /**
+     * Sets the creation time of the entry.
+     *
+     * <p> If set, the creation time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when
+     * output to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The creation time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getCreationTime()
+     * @since 1.8
+     */
+    public ZipEntry setCreationTime(FileTime time) {
+        this.ctime = Objects.requireNonNull(time, "creationTime");
+        return this;
+    }
+
+    /**
+     * Returns the creation time of the entry.
+     *
+     * <p> The creation time is from the extended timestamp fields of
+     * entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return the creation time of the entry, null if not specified
+     * @see #setCreationTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getCreationTime() {
+        return ctime;
+    }
+
+    /**
+     * Sets the uncompressed size of the entry data.
+     *
+     * @param size the uncompressed size in bytes
+     *
+     * @throws IllegalArgumentException if the specified size is less
+     *         than 0, is greater than 0xFFFFFFFF when
+     *         <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
+     *         or is less than 0 when ZIP64 is supported
+     * @see #getSize()
+     */
+    public void setSize(long size) {
+        if (size < 0) {
+            throw new IllegalArgumentException("invalid entry size");
+        }
+        this.size = size;
+    }
+
+    /**
+     * Returns the uncompressed size of the entry data.
+     *
+     * @return the uncompressed size of the entry data, or -1 if not known
+     * @see #setSize(long)
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Returns the size of the compressed entry data.
+     *
+     * <p> In the case of a stored entry, the compressed size will be the same
+     * as the uncompressed size of the entry.
+     *
+     * @return the size of the compressed entry data, or -1 if not known
+     * @see #setCompressedSize(long)
+     */
+    public long getCompressedSize() {
+        return csize;
+    }
+
+    /**
+     * Sets the size of the compressed entry data.
+     *
+     * @param csize the compressed size to set
+     *
+     * @see #getCompressedSize()
+     */
+    public void setCompressedSize(long csize) {
+        this.csize = csize;
+        this.csizeSet = true;
+    }
+
+    /**
+     * Sets the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @param crc the CRC-32 value
+     *
+     * @throws IllegalArgumentException if the specified CRC-32 value is
+     *         less than 0 or greater than 0xFFFFFFFF
+     * @see #getCrc()
+     */
+    public void setCrc(long crc) {
+        if (crc < 0 || crc > 0xFFFFFFFFL) {
+            throw new IllegalArgumentException("invalid entry crc-32");
+        }
+        this.crc = crc;
+    }
+
+    /**
+     * Returns the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
+     * not known
+     *
+     * @see #setCrc(long)
+     */
+    public long getCrc() {
+        return crc;
+    }
+
+    /**
+     * Sets the compression method for the entry.
+     *
+     * @param method the compression method, either STORED or DEFLATED
+     *
+     * @throws  IllegalArgumentException if the specified compression
+     *          method is invalid
+     * @see #getMethod()
+     */
+    public void setMethod(int method) {
+        if (method != STORED && method != DEFLATED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Returns the compression method of the entry.
+     *
+     * @return the compression method of the entry, or -1 if not specified
+     * @see #setMethod(int)
+     */
+    public int getMethod() {
+        return method;
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * <p> Invoking this method may change this entry's last modification
+     * time, last access time and creation time, if the {@code extra} field
+     * data includes the extensible timestamp fields, such as {@code NTFS tag
+     * 0x0001} or {@code Info-ZIP Extended Timestamp}, as specified in
+     * <a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">Info-ZIP
+     * Application Note 970311</a>.
+     *
+     * @param  extra
+     *         The extra field data bytes
+     *
+     * @throws IllegalArgumentException if the length of the specified
+     *         extra field data is greater than 0xFFFF bytes
+     *
+     * @see #getExtra()
+     */
+    public void setExtra(byte[] extra) {
+        setExtra0(extra, false, true);
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * @param extra
+     *        the extra field data bytes
+     * @param doZIP64
+     *        if true, set size and csize from ZIP64 fields if present
+     * @param isLOC
+     *        true if setting the extra field for a LOC, false if for
+     *        a CEN
+     */
+    void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) {
+        if (extra != null) {
+            if (extra.length > 0xFFFF) {
+                throw new IllegalArgumentException("invalid extra field length");
+            }
+            // extra fields are in "HeaderID(2)DataSize(2)Data... format
+            int off = 0;
+            int len = extra.length;
+            while (off + 4 < len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                off += 4;
+                if (off + sz > len)         // invalid data
+                    break;
+                switch (tag) {
+                case EXTID_ZIP64:
+                    if (doZIP64) {
+                        if (isLOC) {
+                            // LOC extra zip64 entry MUST include BOTH original
+                            // and compressed file size fields.
+                            // If invalid zip64 extra fields, simply skip. Even
+                            // it's rare, it's possible the entry size happens to
+                            // be the magic value and it "accidently" has some
+                            // bytes in extra match the id.
+                            if (sz >= 16) {
+                                size = get64(extra, off);
+                                csize = get64(extra, off + 8);
+                            }
+                        } else {
+                            // CEN extra zip64
+                            if (size == ZIP64_MAGICVAL) {
+                                if (off + 8 > len)  // invalid zip64 extra
+                                    break;          // fields, just skip
+                                size = get64(extra, off);
+                            }
+                            if (csize == ZIP64_MAGICVAL) {
+                                if (off + 16 > len)  // invalid zip64 extra
+                                    break;           // fields, just skip
+                                csize = get64(extra, off + 8);
+                            }
+                        }
+                    }
+                    break;
+                case EXTID_NTFS:
+                    if (sz < 32) // reserved  4 bytes + tag 2 bytes + size 2 bytes
+                        break;   // m[a|c]time 24 bytes
+                    int pos = off + 4;               // reserved 4 bytes
+                    if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
+                        break;
+                    long wtime = get64(extra, pos + 4);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        mtime = winTimeToFileTime(wtime);
+                    }
+                    wtime = get64(extra, pos + 12);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        atime = winTimeToFileTime(wtime);
+                    }
+                    wtime = get64(extra, pos + 20);
+                    if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+                        ctime = winTimeToFileTime(wtime);
+                    }
+                    break;
+                case EXTID_EXTT:
+                    int flag = Byte.toUnsignedInt(extra[off]);
+                    int sz0 = 1;
+                    // The CEN-header extra field contains the modification
+                    // time only, or no timestamp at all. 'sz' is used to
+                    // flag its presence or absence. But if mtime is present
+                    // in LOC it must be present in CEN as well.
+                    if ((flag & 0x1) != 0 && (sz0 + 4) <= sz) {
+                        mtime = unixTimeToFileTime(get32S(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x2) != 0 && (sz0 + 4) <= sz) {
+                        atime = unixTimeToFileTime(get32S(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x4) != 0 && (sz0 + 4) <= sz) {
+                        ctime = unixTimeToFileTime(get32S(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    break;
+                 default:
+                }
+                off += sz;
+            }
+        }
+        this.extra = extra;
+    }
+
+    /**
+     * Returns the extra field data for the entry.
+     *
+     * @return the extra field data for the entry, or null if none
+     *
+     * @see #setExtra(byte[])
+     */
+    public byte[] getExtra() {
+        return extra;
+    }
+
+    /**
+     * Sets the optional comment string for the entry.
+     *
+     * <p>ZIP entry comments have maximum length of 0xffff. If the length of the
+     * specified comment string is greater than 0xFFFF bytes after encoding, only
+     * the first 0xFFFF bytes are output to the ZIP file entry.
+     *
+     * @param comment the comment string
+     *
+     * @see #getComment()
+     */
+    public void setComment(String comment) {
+        // BEGIN Android-added: Explicitly use UTF_8 instead of the default charset.
+        if (comment != null && comment.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(comment + " too long: " +
+                    comment.getBytes(StandardCharsets.UTF_8).length);
+        }
+        // END Android-added: Explicitly use UTF_8 instead of the default charset.
+
+        this.comment = comment;
+    }
+
+    /**
+     * Returns the comment string for the entry.
+     *
+     * @return the comment string for the entry, or null if none
+     *
+     * @see #setComment(String)
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Returns true if this is a directory entry. A directory entry is
+     * defined to be one whose name ends with a '/'.
+     * @return true if this is a directory entry
+     */
+    public boolean isDirectory() {
+        return name.endsWith("/");
+    }
+
+    /**
+     * Returns a string representation of the ZIP entry.
+     */
+    public String toString() {
+        return getName();
+    }
+
+    /**
+     * Returns the hash code value for this entry.
+     */
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * Returns a copy of this entry.
+     */
+    public Object clone() {
+        try {
+            ZipEntry e = (ZipEntry)super.clone();
+            e.extra = (extra == null) ? null : extra.clone();
+            return e;
+        } catch (CloneNotSupportedException e) {
+            // This should never happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+}
diff --git a/android-35/java/util/zip/ZipError.java b/android-35/java/util/zip/ZipError.java
new file mode 100644
index 0000000..2aa37be
--- /dev/null
+++ b/android-35/java/util/zip/ZipError.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that an unrecoverable error has occurred.
+ *
+ * @author  Dave Bristor
+ * @since   1.6
+ */
+public class ZipError extends InternalError {
+    @java.io.Serial
+    private static final long serialVersionUID = 853973422266861979L;
+
+    /**
+     * Constructs a ZipError with the given detail message.
+     * @param s the {@code String} containing a detail message
+     */
+    public ZipError(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/zip/ZipException.java b/android-35/java/util/zip/ZipException.java
new file mode 100644
index 0000000..45048a4
--- /dev/null
+++ b/android-35/java/util/zip/ZipException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.IOException;
+
+/**
+ * Signals that a Zip exception of some sort has occurred.
+ *
+ * @see     java.io.IOException
+ * @since   1.1
+ */
+
+public class ZipException extends IOException {
+    @java.io.Serial
+    private static final long serialVersionUID = 8000196834066748623L;
+
+    /**
+     * Constructs a {@code ZipException} with {@code null}
+     * as its error detail message.
+     */
+    public ZipException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code ZipException} with the specified detail
+     * message.
+     *
+     * @param   s   the detail message.
+     */
+
+    public ZipException(String s) {
+        super(s);
+    }
+}
diff --git a/android-35/java/util/zip/ZipFile.java b/android-35/java/util/zip/ZipFile.java
new file mode 100644
index 0000000..ee23e55
--- /dev/null
+++ b/android-35/java/util/zip/ZipFile.java
@@ -0,0 +1,1941 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.RandomAccessFile;
+import java.io.UncheckedIOException;
+import java.lang.ref.Cleaner.Cleanable;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.InvalidPathException;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.Files;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.misc.VM;
+import jdk.internal.ref.CleanerFactory;
+import jdk.internal.vm.annotation.Stable;
+import sun.security.util.SignatureFileVerifier;
+
+import dalvik.system.CloseGuard;
+import dalvik.system.ZipPathValidator;
+
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+/**
+ * This class is used to read entries from a zip file.
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @apiNote
+ * To release resources used by this {@code ZipFile}, the {@link #close()} method
+ * should be called explicitly or by try-with-resources. Subclasses are responsible
+ * for the cleanup of resources acquired by the subclass. Subclasses that override
+ * {@link #finalize()} in order to perform cleanup should be modified to use alternative
+ * cleanup mechanisms such as {@link java.lang.ref.Cleaner} and remove the overriding
+ * {@code finalize} method.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class ZipFile implements ZipConstants, Closeable {
+
+    private final String name;     // zip file name
+    private volatile boolean closeRequested;
+
+    // The "resource" used by this zip file that needs to be
+    // cleaned after use.
+    // a) the input streams that need to be closed
+    // b) the list of cached Inflater objects
+    // c) the "native" source of this zip file.
+    private final @Stable CleanableResource res;
+
+    // Android-added: CloseGuard support.
+    private final CloseGuard guard = CloseGuard.get();
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Mode flag to open a zip file for reading.
+     */
+    public static final int OPEN_READ = 0x1;
+
+    /**
+     * Mode flag to open a zip file and mark it for deletion.  The file will be
+     * deleted some time between the moment that it is opened and the moment
+     * that it is closed, but its contents will remain accessible via the
+     * {@code ZipFile} object until either the close method is invoked or the
+     * virtual machine exits.
+     */
+    public static final int OPEN_DELETE = 0x4;
+
+    // Android-changed: Additional ZipException throw scenario with ZipPathValidator.
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its {@code checkRead}
+     * method is called with the {@code name} argument as its argument
+     * to ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * <p>If the app targets Android U or above, zip file entry names containing
+     * ".." or starting with "/" passed here will throw a {@link ZipException}.
+     * For more details, see {@link dalvik.system.ZipPathValidator}.
+     *
+     * @param name the name of the zip file
+     * @throws ZipException if (1) a ZIP format error has occurred or
+     *         (2) <code>targetSdkVersion >= BUILD.VERSION_CODES.UPSIDE_DOWN_CAKE</code>
+     *         and (the <code>name</code> argument contains ".." or starts with "/").
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and its
+     *         {@code checkRead} method doesn't allow read access to the file.
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     */
+    public ZipFile(String name) throws IOException {
+        this(new File(name), OPEN_READ);
+    }
+
+    /**
+     * Opens a new {@code ZipFile} to read from the specified
+     * {@code File} object in the specified mode.  The mode argument
+     * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
+     *
+     * <p>First, if there is a security manager, its {@code checkRead}
+     * method is called with the {@code name} argument as its argument to
+     * ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and
+     *         its {@code checkRead} method
+     *         doesn't allow read access to the file,
+     *         or its {@code checkDelete} method doesn't allow deleting
+     *         the file when the {@code OPEN_DELETE} flag is set.
+     * @throws IllegalArgumentException if the {@code mode} argument is invalid
+     * @see SecurityManager#checkRead(java.lang.String)
+     * @since 1.3
+     */
+    public ZipFile(File file, int mode) throws IOException {
+        // Android-changed: Use StandardCharsets.UTF_8.
+        // this(file, mode, UTF_8.INSTANCE);
+        this(file, mode, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     */
+    public ZipFile(File file) throws ZipException, IOException {
+        this(file, OPEN_READ);
+    }
+
+    // Android-changed: Use of the hidden constructor with a new argument for zip path validation.
+    /**
+     * Opens a new {@code ZipFile} to read from the specified
+     * {@code File} object in the specified mode.  The mode argument
+     * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
+     *
+     * <p>First, if there is a security manager, its {@code checkRead}
+     * method is called with the {@code name} argument as its argument to
+     * ensure the read is allowed.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @throws SecurityException
+     *         if a security manager exists and its {@code checkRead}
+     *         method doesn't allow read access to the file,or its
+     *         {@code checkDelete} method doesn't allow deleting the
+     *         file when the {@code OPEN_DELETE} flag is set
+     *
+     * @throws IllegalArgumentException if the {@code mode} argument is invalid
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, int mode, Charset charset) throws IOException
+    {
+        this(file, mode, charset, /* enableZipPathValidator */ true);
+    }
+
+    // Android-added: New hidden constructor with an argument for zip path validation.
+    /** @hide */
+    public ZipFile(File file, int mode, boolean enableZipPathValidator) throws IOException {
+        this(file, mode, StandardCharsets.UTF_8, enableZipPathValidator);
+    }
+
+    // Android-changed: Change existing constructor ZipFile(File file, int mode, Charset charset)
+    // to have a new argument enableZipPathValidator in order to set the isZipPathValidatorEnabled
+    // variable before calling the native method open().
+    /** @hide */
+    public ZipFile(File file, int mode, Charset charset, boolean enableZipPathValidator)
+            throws IOException {
+        if (((mode & OPEN_READ) == 0) ||
+            ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
+            throw new IllegalArgumentException("Illegal mode: 0x"+
+                                               Integer.toHexString(mode));
+        }
+        String name = file.getPath();
+        file = new File(name);
+        // Android-removed: SecurityManager is always null.
+        /*
+        @SuppressWarnings("removal")
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkRead(name);
+            if ((mode & OPEN_DELETE) != 0) {
+                sm.checkDelete(name);
+            }
+        }
+        */
+
+        Objects.requireNonNull(charset, "charset");
+
+        this.name = name;
+        // Android-removed: Skip perf counters.
+        // long t0 = System.nanoTime();
+
+        // Android-changed: pass isZipPathValidatorEnabled flag.
+        // this.res = new CleanableResource(this, ZipCoder.get(charset), file, mode);
+        boolean isZipPathValidatorEnabled = enableZipPathValidator && !ZipPathValidator.isClear();
+        this.res = new CleanableResource(
+                this, ZipCoder.get(charset), file, mode, isZipPathValidatorEnabled);
+
+        // Android-removed: Skip perf counters.
+        // PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
+        // PerfCounter.getZipFileCount().increment();
+    }
+
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its {@code checkRead}
+     * method is called with the {@code name} argument as its argument
+     * to ensure the read is allowed.
+     *
+     * @param name the name of the zip file
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException
+     *         if a security manager exists and its {@code checkRead}
+     *         method doesn't allow read access to the file
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(String name, Charset charset) throws IOException
+    {
+        this(new File(name), OPEN_READ, charset);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name and comment (ignored if
+     *        the <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, Charset charset) throws IOException
+    {
+        this(file, OPEN_READ, charset);
+    }
+
+    /**
+     * Returns the zip file comment, or null if none.
+     *
+     * @return the comment string for the zip file, or null if none
+     *
+     * @throws IllegalStateException if the zip file has been closed
+     *
+     * @since 1.7
+     */
+    public String getComment() {
+        synchronized (this) {
+            ensureOpen();
+            if (res.zsrc.comment == null) {
+                return null;
+            }
+            return res.zsrc.zc.toString(res.zsrc.comment);
+        }
+    }
+
+    /**
+     * Returns the zip file entry for the specified name, or null
+     * if not found.
+     *
+     * @param name the name of the entry
+     * @return the zip file entry, or null if not found
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public ZipEntry getEntry(String name) {
+        Objects.requireNonNull(name, "name");
+        ZipEntry entry = null;
+        synchronized (this) {
+            ensureOpen();
+            int pos = res.zsrc.getEntryPos(name, true);
+            if (pos != -1) {
+                entry = getZipEntry(name, pos);
+            }
+        }
+        return entry;
+    }
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     * <p>
+     * Closing this ZIP file will, in turn, close all input streams that
+     * have been returned by invocations of this method.
+     *
+     * @param entry the zip file entry
+     * @return the input stream for reading the contents of the specified
+     * zip file entry.
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public InputStream getInputStream(ZipEntry entry) throws IOException {
+        Objects.requireNonNull(entry, "entry");
+        int pos;
+        ZipFileInputStream in;
+        Source zsrc = res.zsrc;
+        Set<InputStream> istreams = res.istreams;
+        synchronized (this) {
+            ensureOpen();
+            if (Objects.equals(lastEntryName, entry.name)) {
+                pos = lastEntryPos;
+            } else {
+                pos = zsrc.getEntryPos(entry.name, false);
+            }
+            if (pos == -1) {
+                return null;
+            }
+            in = new ZipFileInputStream(zsrc.cen, pos);
+            switch (CENHOW(zsrc.cen, pos)) {
+            case STORED:
+                synchronized (istreams) {
+                    istreams.add(in);
+                }
+                return in;
+            case DEFLATED:
+                // Inflater likes a bit of slack
+                // MORE: Compute good size for inflater stream:
+                long size = CENLEN(zsrc.cen, pos) + 2;
+                if (size > 65536) {
+                    // Android-changed: Use 64k buffer size, performs
+                    // better than 8k. See http://b/65491407.
+                    // size = 8192;
+                    size = 65536;
+                }
+                if (size <= 0) {
+                    size = 4096;
+                }
+                InputStream is = new ZipFileInflaterInputStream(in, res, (int)size);
+                synchronized (istreams) {
+                    istreams.add(is);
+                }
+                return is;
+            default:
+                throw new ZipException("invalid compression method");
+            }
+        }
+    }
+
+    private static class InflaterCleanupAction implements Runnable {
+        private final Inflater inf;
+        private final CleanableResource res;
+
+        InflaterCleanupAction(Inflater inf, CleanableResource res) {
+            this.inf = inf;
+            this.res = res;
+        }
+
+        @Override
+        public void run() {
+            res.releaseInflater(inf);
+        }
+    }
+
+    private class ZipFileInflaterInputStream extends InflaterInputStream {
+        private volatile boolean closeRequested;
+        private boolean eof = false;
+        private final Cleanable cleanable;
+
+        ZipFileInflaterInputStream(ZipFileInputStream zfin,
+                                   CleanableResource res, int size) {
+            this(zfin, res, res.getInflater(), size);
+        }
+
+        private ZipFileInflaterInputStream(ZipFileInputStream zfin,
+                                           CleanableResource res,
+                                           Inflater inf, int size) {
+            // Android-changed: ZipFileInflaterInputStream does not control its inflater's lifetime
+            // and hence it shouldn't be closed when the stream is closed.
+            // super(zfin, inf, size);
+            super(zfin, inf, size, /* ownsInflater */ false);
+            this.cleanable = CleanerFactory.cleaner().register(this,
+                    new InflaterCleanupAction(inf, res));
+        }
+
+        public void close() throws IOException {
+            if (closeRequested)
+                return;
+            closeRequested = true;
+            super.close();
+            synchronized (res.istreams) {
+                res.istreams.remove(this);
+            }
+            cleanable.clean();
+        }
+
+        // Override fill() method to provide an extra "dummy" byte
+        // at the end of the input stream. This is required when
+        // using the "nowrap" Inflater option.
+        protected void fill() throws IOException {
+            if (eof) {
+                throw new EOFException("Unexpected end of ZLIB input stream");
+            }
+            len = in.read(buf, 0, buf.length);
+            if (len == -1) {
+                buf[0] = 0;
+                len = 1;
+                eof = true;
+            }
+            inf.setInput(buf, 0, len);
+        }
+
+        public int available() throws IOException {
+            if (closeRequested)
+                return 0;
+            long avail = ((ZipFileInputStream)in).size() - inf.getBytesWritten();
+            return (avail > (long) Integer.MAX_VALUE ?
+                    Integer.MAX_VALUE : (int) avail);
+        }
+    }
+
+    /**
+     * Returns the path name of the ZIP file.
+     * @return the path name of the ZIP file
+     */
+    public String getName() {
+        return name;
+    }
+
+    private class ZipEntryIterator<T extends ZipEntry>
+            implements Enumeration<T>, Iterator<T> {
+
+        private int i = 0;
+        private final int entryCount;
+
+        public ZipEntryIterator(int entryCount) {
+            this.entryCount = entryCount;
+        }
+
+        @Override
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        @Override
+        public boolean hasNext() {
+            // Android-changed: check that file is open.
+            // return i < entryCount;
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                return i < entryCount;
+            }
+        }
+
+        @Override
+        public T nextElement() {
+            return next();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T next() {
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                // each "entry" has 3 ints in table entries
+                return (T)getZipEntry(null, res.zsrc.getEntryPos(i++ * 3));
+            }
+        }
+
+        @Override
+        public Iterator<T> asIterator() {
+            return this;
+        }
+    }
+
+    /**
+     * Returns an enumeration of the ZIP file entries.
+     * @return an enumeration of the ZIP file entries
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public Enumeration<? extends ZipEntry> entries() {
+        synchronized (this) {
+            ensureOpen();
+            return new ZipEntryIterator<ZipEntry>(res.zsrc.total);
+        }
+    }
+
+    private Enumeration<JarEntry> jarEntries() {
+        synchronized (this) {
+            ensureOpen();
+            return new ZipEntryIterator<JarEntry>(res.zsrc.total);
+        }
+    }
+
+    private class EntrySpliterator<T> extends Spliterators.AbstractSpliterator<T> {
+        private int index;
+        private final int fence;
+        private final IntFunction<T> gen;
+
+        EntrySpliterator(int index, int fence, IntFunction<T> gen) {
+            super((long)fence,
+                  Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE |
+                  Spliterator.NONNULL);
+            this.index = index;
+            this.fence = fence;
+            this.gen = gen;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                synchronized (ZipFile.this) {
+                    ensureOpen();
+                    action.accept(gen.apply(res.zsrc.getEntryPos(index++ * 3)));
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Returns an ordered {@code Stream} over the ZIP file entries.
+     *
+     * Entries appear in the {@code Stream} in the order they appear in
+     * the central directory of the ZIP file.
+     *
+     * @return an ordered {@code Stream} of entries in this ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     * @since 1.8
+     */
+    public Stream<? extends ZipEntry> stream() {
+        synchronized (this) {
+            ensureOpen();
+            return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
+                pos -> getZipEntry(null, pos)), false);
+       }
+    }
+
+    private String getEntryName(int pos) {
+        byte[] cen = res.zsrc.cen;
+        int nlen = CENNAM(cen, pos);
+        ZipCoder zc = res.zsrc.zipCoderForPos(pos);
+        return zc.toString(cen, pos + CENHDR, nlen);
+    }
+
+    /*
+     * Returns an ordered {@code Stream} over the zip file entry names.
+     *
+     * Entry names appear in the {@code Stream} in the order they appear in
+     * the central directory of the ZIP file.
+     *
+     * @return an ordered {@code Stream} of entry names in this zip file
+     * @throws IllegalStateException if the zip file has been closed
+     * @since 10
+     */
+    private Stream<String> entryNameStream() {
+        synchronized (this) {
+            ensureOpen();
+            return StreamSupport.stream(
+                new EntrySpliterator<>(0, res.zsrc.total, this::getEntryName), false);
+        }
+    }
+
+    /*
+     * Returns an ordered {@code Stream} over the zip file entries.
+     *
+     * Entries appear in the {@code Stream} in the order they appear in
+     * the central directory of the jar file.
+     *
+     * @return an ordered {@code Stream} of entries in this zip file
+     * @throws IllegalStateException if the zip file has been closed
+     * @since 10
+     */
+    private Stream<JarEntry> jarStream() {
+        synchronized (this) {
+            ensureOpen();
+            return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
+                pos -> (JarEntry)getZipEntry(null, pos)), false);
+        }
+    }
+
+    private String lastEntryName;
+    private int lastEntryPos;
+
+    /* Check ensureOpen() before invoking this method */
+    private ZipEntry getZipEntry(String name, int pos) {
+        byte[] cen = res.zsrc.cen;
+        int nlen = CENNAM(cen, pos);
+        int elen = CENEXT(cen, pos);
+        int clen = CENCOM(cen, pos);
+
+        ZipCoder zc = res.zsrc.zipCoderForPos(pos);
+        if (name != null) {
+            // only need to check for mismatch of trailing slash
+            if (nlen > 0 &&
+                !name.isEmpty() &&
+                zc.hasTrailingSlash(cen, pos + CENHDR + nlen) &&
+                !name.endsWith("/"))
+            {
+                name += '/';
+            }
+        } else {
+            // invoked from iterator, use the entry name stored in cen
+            name = zc.toString(cen, pos + CENHDR, nlen);
+        }
+        ZipEntry e;
+        if (this instanceof JarFile) {
+            // Android-changed: access method directly.
+            // e = Source.JUJA.entryFor((JarFile)this, name);
+            e = ((JarFile) this).entryFor(name);
+        } else {
+            e = new ZipEntry(name);
+        }
+        e.flag = CENFLG(cen, pos);
+        e.xdostime = CENTIM(cen, pos);
+        e.crc = CENCRC(cen, pos);
+        e.size = CENLEN(cen, pos);
+        e.csize = CENSIZ(cen, pos);
+        e.method = CENHOW(cen, pos);
+        if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) {
+            // read all bits in this field, including sym link attributes
+            e.extraAttributes = CENATX_PERMS(cen, pos) & 0xFFFF;
+        }
+
+        if (elen != 0) {
+            int start = pos + CENHDR + nlen;
+            e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true, false);
+        }
+        if (clen != 0) {
+            int start = pos + CENHDR + nlen + elen;
+            e.comment = zc.toString(cen, start, clen);
+        }
+        lastEntryName = e.name;
+        lastEntryPos = pos;
+        return e;
+    }
+
+    /**
+     * Returns the number of entries in the ZIP file.
+     *
+     * @return the number of entries in the ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public int size() {
+        synchronized (this) {
+            ensureOpen();
+            return res.zsrc.total;
+        }
+    }
+
+    private static class CleanableResource implements Runnable {
+        // The outstanding inputstreams that need to be closed
+        final Set<InputStream> istreams;
+
+        // List of cached Inflater objects for decompression
+        Deque<Inflater> inflaterCache;
+
+        final Cleanable cleanable;
+
+        Source zsrc;
+
+        CleanableResource(ZipFile zf, ZipCoder zc, File file, int mode) throws IOException {
+            this(zf, zc, file, mode, false);
+        }
+
+        // Android-added: added extra enableZipPathValidator argument.
+        CleanableResource(ZipFile zf, ZipCoder zc, File file,
+                int mode, boolean enableZipPathValidator) throws IOException {
+            this.cleanable = CleanerFactory.cleaner().register(zf, this);
+            this.istreams = Collections.newSetFromMap(new WeakHashMap<>());
+            this.inflaterCache = new ArrayDeque<>();
+            this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0, zc, enableZipPathValidator);
+        }
+
+        void clean() {
+            cleanable.clean();
+        }
+
+        /*
+         * Gets an inflater from the list of available inflaters or allocates
+         * a new one.
+         */
+        Inflater getInflater() {
+            Inflater inf;
+            synchronized (inflaterCache) {
+                if ((inf = inflaterCache.poll()) != null) {
+                    return inf;
+                }
+            }
+            return new Inflater(true);
+        }
+
+        /*
+         * Releases the specified inflater to the list of available inflaters.
+         */
+        void releaseInflater(Inflater inf) {
+            Deque<Inflater> inflaters = this.inflaterCache;
+            if (inflaters != null) {
+                synchronized (inflaters) {
+                    // double checked!
+                    if (inflaters == this.inflaterCache) {
+                        inf.reset();
+                        inflaters.add(inf);
+                        return;
+                    }
+                }
+            }
+            // inflaters cache already closed - just end it.
+            inf.end();
+        }
+
+        public void run() {
+            IOException ioe = null;
+
+            // Release cached inflaters and close the cache first
+            Deque<Inflater> inflaters = this.inflaterCache;
+            if (inflaters != null) {
+                synchronized (inflaters) {
+                    // no need to double-check as only one thread gets a
+                    // chance to execute run() (Cleaner guarantee)...
+                    Inflater inf;
+                    while ((inf = inflaters.poll()) != null) {
+                        inf.end();
+                    }
+                    // close inflaters cache
+                    this.inflaterCache = null;
+                }
+            }
+
+            // Close streams, release their inflaters
+            if (istreams != null) {
+                synchronized (istreams) {
+                    if (!istreams.isEmpty()) {
+                        InputStream[] copy = istreams.toArray(new InputStream[0]);
+                        istreams.clear();
+                        for (InputStream is : copy) {
+                            try {
+                                is.close();
+                            } catch (IOException e) {
+                                if (ioe == null) ioe = e;
+                                else ioe.addSuppressed(e);
+                            }
+                        }
+                    }
+                }
+            }
+
+            // Release zip src
+            if (zsrc != null) {
+                synchronized (zsrc) {
+                    try {
+                        Source.release(zsrc);
+                        zsrc = null;
+                    } catch (IOException e) {
+                        if (ioe == null) ioe = e;
+                        else ioe.addSuppressed(e);
+                    }
+                }
+            }
+            if (ioe != null) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+    }
+
+    /**
+     * Closes the ZIP file.
+     *
+     * <p> Closing this ZIP file will close all of the input streams
+     * previously returned by invocations of the {@link #getInputStream
+     * getInputStream} method.
+     *
+     * @throws IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (closeRequested) {
+            return;
+        }
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.close();
+        }
+        closeRequested = true;
+
+        synchronized (this) {
+            // Close streams, release their inflaters, release cached inflaters
+            // and release zip source
+            try {
+                res.clean();
+            } catch (UncheckedIOException ioe) {
+                throw ioe.getCause();
+            }
+        }
+    }
+
+    private void ensureOpen() {
+        if (closeRequested) {
+            throw new IllegalStateException("zip file closed");
+        }
+        if (res.zsrc == null) {
+            throw new IllegalStateException("The object is not initialized.");
+        }
+    }
+
+    private void ensureOpenOrZipException() throws IOException {
+        if (closeRequested) {
+            throw new ZipException("ZipFile closed");
+        }
+    }
+
+    /*
+     * Inner class implementing the input stream used to read a
+     * (possibly compressed) zip file entry.
+     */
+    private class ZipFileInputStream extends InputStream {
+        private volatile boolean closeRequested;
+        private   long pos;     // current position within entry data
+        private   long startingPos; // Start position for the entry data
+        protected long rem;     // number of remaining bytes within entry
+        protected long size;    // uncompressed size of this entry
+
+        ZipFileInputStream(byte[] cen, int cenpos) {
+            rem = CENSIZ(cen, cenpos);
+            size = CENLEN(cen, cenpos);
+            pos = CENOFF(cen, cenpos);
+            // zip64
+            if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
+                pos == ZIP64_MAGICVAL) {
+                checkZIP64(cen, cenpos);
+            }
+            // negative for lazy initialization, see getDataOffset();
+            pos = - (pos + ZipFile.this.res.zsrc.locpos);
+        }
+
+        private void checkZIP64(byte[] cen, int cenpos) {
+            int off = cenpos + CENHDR + CENNAM(cen, cenpos);
+            int end = off + CENEXT(cen, cenpos);
+            while (off + 4 < end) {
+                int tag = get16(cen, off);
+                int sz = get16(cen, off + 2);
+                off += 4;
+                if (off + sz > end)         // invalid data
+                    break;
+                if (tag == EXTID_ZIP64) {
+                    if (size == ZIP64_MAGICVAL) {
+                        if (sz < 8 || (off + 8) > end)
+                            break;
+                        size = get64(cen, off);
+                        sz -= 8;
+                        off += 8;
+                    }
+                    if (rem == ZIP64_MAGICVAL) {
+                        if (sz < 8 || (off + 8) > end)
+                            break;
+                        rem = get64(cen, off);
+                        sz -= 8;
+                        off += 8;
+                    }
+                    if (pos == ZIP64_MAGICVAL) {
+                        if (sz < 8 || (off + 8) > end)
+                            break;
+                        pos = get64(cen, off);
+                        sz -= 8;
+                        off += 8;
+                    }
+                    break;
+                }
+                off += sz;
+            }
+        }
+
+        /*
+         * The Zip file spec explicitly allows the LOC extra data size to
+         * be different from the CEN extra data size. Since we cannot trust
+         * the CEN extra data size, we need to read the LOC to determine
+         * the entry data offset.
+         */
+        private long initDataOffset() throws IOException {
+            if (pos <= 0) {
+                byte[] loc = new byte[LOCHDR];
+                pos = -pos;
+                int len = ZipFile.this.res.zsrc.readFullyAt(loc, 0, loc.length, pos);
+                if (len != LOCHDR) {
+                    throw new ZipException("ZipFile error reading zip file");
+                }
+                if (LOCSIG(loc) != LOCSIG) {
+                    throw new ZipException("ZipFile invalid LOC header (bad signature)");
+                }
+                pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
+                startingPos = pos; // Save starting position for the entry
+            }
+            return pos;
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            synchronized (ZipFile.this) {
+                ensureOpenOrZipException();
+                initDataOffset();
+                if (rem == 0) {
+                    return -1;
+                }
+                if (len > rem) {
+                    len = (int) rem;
+                }
+                if (len <= 0) {
+                    return 0;
+                }
+                len = ZipFile.this.res.zsrc.readAt(b, off, len, pos);
+                if (len > 0) {
+                    pos += len;
+                    rem -= len;
+                }
+            }
+            if (rem == 0) {
+                close();
+            }
+            return len;
+        }
+
+        public int read() throws IOException {
+            byte[] b = new byte[1];
+            if (read(b, 0, 1) == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public long skip(long n) throws IOException {
+            synchronized (ZipFile.this) {
+                initDataOffset();
+                long newPos = pos + n;
+                if (n > 0) {
+                    // If we overflowed adding the skip value or are moving
+                    // past EOF, set the skip value to number of bytes remaining
+                    // to reach EOF
+                    if (newPos < 0 || n > rem) {
+                        n = rem;
+                    }
+                } else if (newPos < startingPos) {
+                    // Tried to position before BOF so set position to the
+                    // BOF and return the number of bytes we moved backwards
+                    // to reach BOF
+                    n = startingPos - pos;
+                }
+                pos += n;
+                rem -= n;
+            }
+            if (rem == 0) {
+                close();
+            }
+            return n;
+        }
+
+        public int available() {
+            return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
+        }
+
+        public long size() {
+            return size;
+        }
+
+        public void close() {
+            if (closeRequested) {
+                return;
+            }
+            closeRequested = true;
+            rem = 0;
+            synchronized (res.istreams) {
+                res.istreams.remove(this);
+            }
+        }
+
+    }
+
+    /**
+     * Returns {@code true} if, and only if, the zip file begins with {@code
+     * LOCSIG}.
+     * @hide
+     */
+    // Android-added: Access startsWithLocHeader() directly.
+    // Make hidden public for use by sun.misc.URLClassPath
+    public boolean startsWithLocHeader() {
+        return res.zsrc.startsWithLoc;
+    }
+
+    // Android-changed: marked as protected so JarFile can access it.
+    /**
+     * Returns the names of the META-INF/MANIFEST.MF entry - if exists -
+     * and any signature-related files under META-INF. This method is used in
+     * JarFile, via SharedSecrets, as an optimization.
+     * @hide
+     */
+    protected List<String> getManifestAndSignatureRelatedFiles() {
+        synchronized (this) {
+            ensureOpen();
+            Source zsrc = res.zsrc;
+            int[] metanames = zsrc.signatureMetaNames;
+            List<String> files = null;
+            if (zsrc.manifestPos >= 0) {
+                files = new ArrayList<>();
+                files.add(getEntryName(zsrc.manifestPos));
+            }
+            if (metanames != null) {
+                if (files == null) {
+                    files = new ArrayList<>();
+                }
+                for (int i = 0; i < metanames.length; i++) {
+                    files.add(getEntryName(metanames[i]));
+                }
+            }
+            return files == null ? List.of() : files;
+        }
+    }
+
+    /**
+     * Returns the number of the META-INF/MANIFEST.MF entries, case insensitive.
+     * When this number is greater than 1, JarVerifier will treat a file as
+     * unsigned.
+     */
+    private int getManifestNum() {
+        synchronized (this) {
+            ensureOpen();
+            return res.zsrc.manifestNum;
+        }
+    }
+
+    // Android-changed: marked public and @hide as alternative to JavaUtilZipFileAccess.getManifestName.
+    /**
+     * Returns the name of the META-INF/MANIFEST.MF entry, ignoring
+     * case. If {@code onlyIfSignatureRelatedFiles} is true, we only return the
+     * manifest if there is also at least one signature-related file.
+     * This method is used in JarFile, via SharedSecrets, as an optimization
+     * when looking up the manifest file.
+     * @hide
+     */
+    protected String getManifestName(boolean onlyIfSignatureRelatedFiles) {
+        synchronized (this) {
+            ensureOpen();
+            Source zsrc = res.zsrc;
+            int pos = zsrc.manifestPos;
+            if (pos >= 0 && (!onlyIfSignatureRelatedFiles || zsrc.signatureMetaNames != null)) {
+                return getEntryName(pos);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the versions for which there exists a non-directory
+     * entry that begin with "META-INF/versions/" (case ignored).
+     * This method is used in JarFile, via SharedSecrets, as an
+     * optimization when looking up potentially versioned entries.
+     * Returns an empty array if no versioned entries exist.
+     */
+    private int[] getMetaInfVersions() {
+        synchronized (this) {
+            ensureOpen();
+            return res.zsrc.metaVersions;
+        }
+    }
+
+    // Android-removed: this code does not run on Windows and JavaUtilZipFileAccess is not imported.
+    /*
+    private static boolean isWindows;
+
+    static {
+        SharedSecrets.setJavaUtilZipFileAccess(
+            new JavaUtilZipFileAccess() {
+                @Override
+                public boolean startsWithLocHeader(ZipFile zip) {
+                    return zip.res.zsrc.startsWithLoc;
+                }
+                @Override
+                public List<String> getManifestAndSignatureRelatedFiles(JarFile jar) {
+                    return ((ZipFile)jar).getManifestAndSignatureRelatedFiles();
+                }
+                @Override
+                public int getManifestNum(JarFile jar) {
+                    return ((ZipFile)jar).getManifestNum();
+                }
+                @Override
+                public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFiles) {
+                    return ((ZipFile)jar).getManifestName(onlyIfHasSignatureRelatedFiles);
+                }
+                @Override
+                public int[] getMetaInfVersions(JarFile jar) {
+                    return ((ZipFile)jar).getMetaInfVersions();
+                }
+                @Override
+                public Enumeration<JarEntry> entries(ZipFile zip) {
+                    return zip.jarEntries();
+                }
+                @Override
+                public Stream<JarEntry> stream(ZipFile zip) {
+                    return zip.jarStream();
+                }
+                @Override
+                public Stream<String> entryNameStream(ZipFile zip) {
+                    return zip.entryNameStream();
+                }
+                @Override
+                public int getExtraAttributes(ZipEntry ze) {
+                    return ze.extraAttributes;
+                }
+                @Override
+                public void setExtraAttributes(ZipEntry ze, int extraAttrs) {
+                    ze.extraAttributes = extraAttrs;
+                }
+
+             }
+        );
+        isWindows = VM.getSavedProperty("os.name").contains("Windows");
+    }
+    */
+
+    private static class Source {
+        // While this is only used from ZipFile, defining it there would cause
+        // a bootstrap cycle that would leave this initialized as null
+        // Android-removed: JavaUtilJarAccess is not available.
+        // private static final JavaUtilJarAccess JUJA = SharedSecrets.javaUtilJarAccess();
+        // "META-INF/".length()
+        private static final int META_INF_LEN = 9;
+        private static final int[] EMPTY_META_VERSIONS = new int[0];
+
+        private final Key key;               // the key in files
+        private final @Stable ZipCoder zc;   // zip coder used to decode/encode
+
+        private int refs = 1;
+
+        private RandomAccessFile zfile;      // zfile of the underlying zip file
+        private byte[] cen;                  // CEN & ENDHDR
+        private long locpos;                 // position of first LOC header (usually 0)
+        private byte[] comment;              // zip file comment
+                                             // list of meta entries in META-INF dir
+        private int   manifestPos = -1;      // position of the META-INF/MANIFEST.MF, if exists
+        private int   manifestNum = 0;       // number of META-INF/MANIFEST.MF, case insensitive
+        private int[] signatureMetaNames;    // positions of signature related entries, if such exist
+        private int[] metaVersions;          // list of unique versions found in META-INF/versions/
+        private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
+
+        // A Hashmap for all entries.
+        //
+        // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
+        // We might have a lot of these in a typical system. In order to save space we don't
+        // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
+        // entry name and its offset {@code pos} in the central directory hdeader.
+        //
+        // private static class Entry {
+        //     int hash;       // 32 bit hashcode on name
+        //     int next;       // hash chain: index into entries
+        //     int pos;        // Offset of central directory file header
+        // }
+        // private Entry[] entries;             // array of hashed cen entry
+        //
+        // To reduce the total size of entries further, we use a int[] here to store 3 "int"
+        // {@code hash}, {@code next} and {@code pos} for each entry. The entry can then be
+        // referred by their index of their positions in the {@code entries}.
+        //
+        private int[] entries;                  // array of hashed cen entry
+
+        // Checks the entry at offset pos in the CEN, calculates the Entry values as per above,
+        // then returns the length of the entry name.
+        private int checkAndAddEntry(int pos, int index)
+            throws ZipException
+        {
+            byte[] cen = this.cen;
+            if (CENSIG(cen, pos) != CENSIG) {
+                zerror("invalid CEN header (bad signature)");
+            }
+            int method = CENHOW(cen, pos);
+            int flag   = CENFLG(cen, pos);
+            if ((flag & 1) != 0) {
+                zerror("invalid CEN header (encrypted entry)");
+            }
+            if (method != STORED && method != DEFLATED) {
+                zerror("invalid CEN header (bad compression method: " + method + ")");
+            }
+            int entryPos = pos + CENHDR;
+            int nlen = CENNAM(cen, pos);
+            if (entryPos + nlen > cen.length - ENDHDR) {
+                zerror("invalid CEN header (bad header size)");
+            }
+            try {
+                ZipCoder zcp = zipCoderForPos(pos);
+                int hash = zcp.checkedHash(cen, entryPos, nlen);
+                int hsh = (hash & 0x7fffffff) % tablelen;
+                int next = table[hsh];
+                table[hsh] = index;
+                // Record the CEN offset and the name hash in our hash cell.
+                entries[index++] = hash;
+                entries[index++] = next;
+                entries[index  ] = pos;
+            } catch (Exception e) {
+                zerror("invalid CEN header (bad entry name)");
+            }
+            return nlen;
+        }
+
+        private int getEntryHash(int index) { return entries[index]; }
+        private int getEntryNext(int index) { return entries[index + 1]; }
+        private int getEntryPos(int index)  { return entries[index + 2]; }
+        private static final int ZIP_ENDCHAIN  = -1;
+        private int total;                   // total number of entries
+        private int[] table;                 // Hash chain heads: indexes into entries
+        private int tablelen;                // number of hash heads
+
+        // Android-changed: isZipFilePathValidatorEnabled added as Key part. Key is used as key in
+        // files HashMap, so not including it could lead to opening ZipFile w/o entry names
+        // validation.
+        private static class Key {
+            final BasicFileAttributes attrs;
+            File file;
+            final boolean utf8;
+            // Android-added: isZipFilePathValidatorEnabled added as Key part.
+            final boolean isZipFilePathValidatorEnabled;
+
+            public Key(File file, BasicFileAttributes attrs, ZipCoder zc) {
+                this(file, attrs, zc, /* isZipFilePathValidatorEnabled= */ false);
+            }
+
+            // Android-added: added constructor with isZipFilePathValidatorEnabled argument.
+            public Key(File file, BasicFileAttributes attrs, ZipCoder zc,
+                    boolean isZipFilePathValidatorEnabled) {
+                this.attrs = attrs;
+                this.file = file;
+                this.utf8 = zc.isUTF8();
+                this.isZipFilePathValidatorEnabled = isZipFilePathValidatorEnabled;
+            }
+
+            public int hashCode() {
+                long t = utf8 ? 0 : Long.MAX_VALUE;
+                t += attrs.lastModifiedTime().toMillis();
+                // Android-changed: include izZipFilePathValidatorEnabled in hash computation.
+                // return ((int)(t ^ (t >>> 32))) + file.hashCode();
+                return ((int)(t ^ (t >>> 32))) + file.hashCode()
+                        + Boolean.hashCode(isZipFilePathValidatorEnabled);
+            }
+
+            public boolean equals(Object obj) {
+                if (obj instanceof Key key) {
+                    if (key.utf8 != utf8) {
+                        return false;
+                    }
+                    if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
+                        return false;
+                    }
+                    // Android-added: include isZipFilePathValidatorEnabled as equality part.
+                    if (key.isZipFilePathValidatorEnabled != isZipFilePathValidatorEnabled) {
+                        return false;
+                    }
+                    Object fk = attrs.fileKey();
+                    if (fk != null) {
+                        return fk.equals(key.attrs.fileKey());
+                    } else {
+                        return file.equals(key.file);
+                    }
+                }
+                return false;
+            }
+        }
+        private static final HashMap<Key, Source> files = new HashMap<>();
+
+
+        // Android-changed: pass izZipFilePathValidatorEnabled argument.
+        // static Source get(File file, boolean toDelete, ZipCoder zc) throws IOException {
+        static Source get(File file, boolean toDelete, ZipCoder zc,
+                boolean isZipPathValidatorEnabled) throws IOException {
+            final Key key;
+            try {
+                // BEGIN Android-changed: isZipFilePathValidatorEnabled passed as part of Key.
+                /*
+                key = new Key(file,
+                        Files.readAttributes(file.toPath(), BasicFileAttributes.class),
+                        zc);
+                */
+                key = new Key(file,
+                        Files.readAttributes(file.toPath(), BasicFileAttributes.class),
+                        zc, isZipPathValidatorEnabled);
+                // END Android-changed: isZipFilePathValidatorEnabled passed as part of Key.
+            } catch (InvalidPathException ipe) {
+                throw new IOException(ipe);
+            }
+            Source src;
+            synchronized (files) {
+                src = files.get(key);
+                if (src != null) {
+                    src.refs++;
+                    return src;
+                }
+            }
+            src = new Source(key, toDelete, zc);
+
+            synchronized (files) {
+                if (files.containsKey(key)) {    // someone else put in first
+                    src.close();                 // close the newly created one
+                    src = files.get(key);
+                    src.refs++;
+                    return src;
+                }
+                files.put(key, src);
+                return src;
+            }
+        }
+
+        static void release(Source src) throws IOException {
+            synchronized (files) {
+                if (src != null && --src.refs == 0) {
+                    files.remove(src.key);
+                    src.close();
+                }
+            }
+        }
+
+        private Source(Key key, boolean toDelete, ZipCoder zc) throws IOException {
+            this.zc = zc;
+            this.key = key;
+            if (toDelete) {
+                // BEGIN Android-changed: we are not targeting Windows, keep else branch only. Also
+                // open file with O_CLOEXEC flag set.
+                /*
+                if (isWindows) {
+                    this.zfile = SharedSecrets.getJavaIORandomAccessFileAccess()
+                                              .openAndDelete(key.file, "r");
+                } else {
+                    this.zfile = new RandomAccessFile(key.file, "r");
+                    key.file.delete();
+                }
+                */
+                this.zfile = new RandomAccessFile(key.file, "r", /* setCloExecFlag= */ true);
+                key.file.delete();
+                // END Android-changed: we are not targeting Windows, keep else branch only.
+            } else {
+                // Android-changed: open with O_CLOEXEC flag set.
+                // this.zfile = new RandomAccessFile(key.file, "r");
+                this.zfile = new RandomAccessFile(key.file, "r", /* setCloExecFlag= */ true);
+            }
+            try {
+                initCEN(-1);
+                byte[] buf = new byte[4];
+                readFullyAt(buf, 0, 4, 0);
+                // BEGIN Android-changed: do not accept files with invalid header
+                // this.startsWithLoc = (LOCSIG(buf) == LOCSIG);
+                long locsig = LOCSIG(buf);
+                this.startsWithLoc = (locsig == LOCSIG);
+                // If a zip file starts with "end of central directory record" it means that such
+                // file is empty.
+                if (locsig != LOCSIG && locsig != ENDSIG) {
+                    String msg = "Entry at offset zero has invalid LFH signature "
+                                    + Long.toHexString(locsig);
+                    throw new ZipException(msg);
+                }
+                // END Android-changed: do not accept files with invalid header
+            } catch (IOException x) {
+                try {
+                    this.zfile.close();
+                } catch (IOException xx) {}
+                throw x;
+            }
+        }
+
+        private void close() throws IOException {
+            zfile.close();
+            zfile = null;
+            cen = null;
+            entries = null;
+            table = null;
+            manifestPos = -1;
+            manifestNum = 0;
+            signatureMetaNames = null;
+            metaVersions = EMPTY_META_VERSIONS;
+        }
+
+        private static final int BUF_SIZE = 8192;
+        private final int readFullyAt(byte[] buf, int off, int len, long pos)
+            throws IOException
+        {
+            synchronized (zfile) {
+                zfile.seek(pos);
+                int N = len;
+                while (N > 0) {
+                    int n = Math.min(BUF_SIZE, N);
+                    zfile.readFully(buf, off, n);
+                    off += n;
+                    N -= n;
+                }
+                return len;
+            }
+        }
+
+        private final int readAt(byte[] buf, int off, int len, long pos)
+            throws IOException
+        {
+            synchronized (zfile) {
+                zfile.seek(pos);
+                return zfile.read(buf, off, len);
+            }
+        }
+
+
+        private static class End {
+            int  centot;     // 4 bytes
+            long cenlen;     // 4 bytes
+            long cenoff;     // 4 bytes
+            long endpos;     // 4 bytes
+        }
+
+        /*
+         * Searches for end of central directory (END) header. The contents of
+         * the END header will be read and placed in endbuf. Returns the file
+         * position of the END header, otherwise returns -1 if the END header
+         * was not found or an error occurred.
+         */
+        private End findEND() throws IOException {
+            long ziplen = zfile.length();
+            if (ziplen <= 0)
+                zerror("zip file is empty");
+            End end = new End();
+            byte[] buf = new byte[READBLOCKSZ];
+            long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0;
+            long minPos = minHDR - (buf.length - ENDHDR);
+            for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) {
+                int off = 0;
+                if (pos < 0) {
+                    // Pretend there are some NUL bytes before start of file
+                    off = (int)-pos;
+                    Arrays.fill(buf, 0, off, (byte)0);
+                }
+                int len = buf.length - off;
+                if (readFullyAt(buf, off, len, pos + off) != len ) {
+                    zerror("zip END header not found");
+                }
+                // Now scan the block backwards for END header signature
+                for (int i = buf.length - ENDHDR; i >= 0; i--) {
+                    if (buf[i+0] == (byte)'P'    &&
+                        buf[i+1] == (byte)'K'    &&
+                        buf[i+2] == (byte)'\005' &&
+                        buf[i+3] == (byte)'\006') {
+                        // Found ENDSIG header
+                        byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR);
+                        end.centot = ENDTOT(endbuf);
+                        end.cenlen = ENDSIZ(endbuf);
+                        end.cenoff = ENDOFF(endbuf);
+                        end.endpos = pos + i;
+                        int comlen = ENDCOM(endbuf);
+                        if (end.endpos + ENDHDR + comlen != ziplen) {
+                            // ENDSIG matched, however the size of file comment in it does
+                            // not match the real size. One "common" cause for this problem
+                            // is some "extra" bytes are padded at the end of the zipfile.
+                            // Let's do some extra verification, we don't care about the
+                            // performance in this situation.
+                            byte[] sbuf = new byte[4];
+                            long cenpos = end.endpos - end.cenlen;
+                            long locpos = cenpos - end.cenoff;
+                            if  (cenpos < 0 ||
+                                 locpos < 0 ||
+                                 readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 ||
+                                 GETSIG(sbuf) != CENSIG ||
+                                 readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 ||
+                                 GETSIG(sbuf) != LOCSIG) {
+                                continue;
+                            }
+                        }
+                        if (comlen > 0) {    // this zip file has comlen
+                            comment = new byte[comlen];
+                            if (readFullyAt(comment, 0, comlen, end.endpos + ENDHDR) != comlen) {
+                                zerror("zip comment read failed");
+                            }
+                        }
+                        // must check for a zip64 end record; it is always permitted to be present
+                        try {
+                            byte[] loc64 = new byte[ZIP64_LOCHDR];
+                            if (end.endpos < ZIP64_LOCHDR ||
+                                readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
+                                != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
+                                return end;
+                            }
+                            long end64pos = ZIP64_LOCOFF(loc64);
+                            byte[] end64buf = new byte[ZIP64_ENDHDR];
+                            if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
+                                != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
+                                return end;
+                            }
+                            // end64 candidate found,
+                            long cenlen64 = ZIP64_ENDSIZ(end64buf);
+                            long cenoff64 = ZIP64_ENDOFF(end64buf);
+                            long centot64 = ZIP64_ENDTOT(end64buf);
+                            // double-check
+                            if (cenlen64 != end.cenlen && end.cenlen != ZIP64_MAGICVAL ||
+                                cenoff64 != end.cenoff && end.cenoff != ZIP64_MAGICVAL ||
+                                centot64 != end.centot && end.centot != ZIP64_MAGICCOUNT) {
+                                return end;
+                            }
+                            // to use the end64 values
+                            end.cenlen = cenlen64;
+                            end.cenoff = cenoff64;
+                            end.centot = (int)centot64; // assume total < 2g
+                            end.endpos = end64pos;
+                        } catch (IOException x) {}    // no zip64 loc/end
+                        return end;
+                    }
+                }
+            }
+            throw new ZipException("zip END header not found");
+        }
+
+        // Reads zip file central directory.
+        private void initCEN(int knownTotal) throws IOException {
+            // Prefer locals for better performance during startup
+            byte[] cen;
+            if (knownTotal == -1) {
+                End end = findEND();
+                if (end.endpos == 0) {
+                    locpos = 0;
+                    total = 0;
+                    entries = new int[0];
+                    this.cen = null;
+                    return;         // only END header present
+                }
+                if (end.cenlen > end.endpos)
+                    zerror("invalid END header (bad central directory size)");
+                long cenpos = end.endpos - end.cenlen;     // position of CEN table
+                // Get position of first local file (LOC) header, taking into
+                // account that there may be a stub prefixed to the zip file.
+                locpos = cenpos - end.cenoff;
+                if (locpos < 0) {
+                    zerror("invalid END header (bad central directory offset)");
+                }
+                // read in the CEN and END
+                cen = this.cen = new byte[(int)(end.cenlen + ENDHDR)];
+                if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
+                    zerror("read CEN tables failed");
+                }
+                this.total = end.centot;
+            } else {
+                cen = this.cen;
+                this.total = knownTotal;
+            }
+            // hash table for entries
+            int entriesLength = this.total * 3;
+            entries = new int[entriesLength];
+
+            int tablelen = ((total/2) | 1); // Odd -> fewer collisions
+            this.tablelen = tablelen;
+
+            int[] table = new int[tablelen];
+            this.table = table;
+
+            Arrays.fill(table, ZIP_ENDCHAIN);
+
+            // list for all meta entries
+            ArrayList<Integer> signatureNames = null;
+            // Set of all version numbers seen in META-INF/versions/
+            Set<Integer> metaVersionsSet = null;
+
+            // Iterate through the entries in the central directory
+            int idx = 0; // Index into the entries array
+            int pos = 0;
+            int entryPos = CENHDR;
+            int limit = cen.length - ENDHDR;
+            manifestNum = 0;
+            // Android-added: duplicate entries are not allowed. See CVE-2013-4787 and b/8219321
+            Set<String> entriesNames = new HashSet<>();
+            while (entryPos <= limit) {
+                if (idx >= entriesLength) {
+                    // This will only happen if the zip file has an incorrect
+                    // ENDTOT field, which usually means it contains more than
+                    // 65535 entries.
+                    initCEN(countCENHeaders(cen, limit));
+                    return;
+                }
+
+                // Checks the entry and adds values to entries[idx ... idx+2]
+                int nlen = checkAndAddEntry(pos, idx);
+
+                // BEGIN Android-added: duplicate entries are not allowed. See CVE-2013-4787
+                // and b/8219321.
+                // zipCoderForPos takes USE_UTF8 flag into account.
+                ZipCoder zcp = zipCoderForPos(entryPos);
+                String name = zcp.toString(cen, pos + CENHDR, nlen);
+                if (!entriesNames.add(name)) {
+                    zerror("Duplicate entry name: " + name);
+                }
+                // END Android-added: duplicate entries are not allowed. See CVE-2013-4787
+                // and b/8219321
+                // BEGIN Android-added: don't allow NUL in entry names. We can handle it in Java fine,
+                // but it is of questionable utility as a valid pathname can't contain NUL.
+                for (int nameIdx = 0; nameIdx < nlen; ++nameIdx) {
+                    byte b = cen[pos + CENHDR + nameIdx];
+
+                    if (b == 0) {
+                        zerror("Filename contains NUL byte: " + name);
+                    }
+                }
+                // END Android-added: don't allow NUL in entry names.
+                // BEGIN Android-changed: validation of zip entry names.
+                if (key.isZipFilePathValidatorEnabled && !ZipPathValidator.isClear()) {
+                    ZipPathValidator.getInstance().onZipEntryAccess(name);
+                }
+                // END Android-changed: validation of zip entry names.
+                idx += 3;
+
+                // Adds name to metanames.
+                if (isMetaName(cen, entryPos, nlen)) {
+                    // nlen is at least META_INF_LENGTH
+                    if (isManifestName(entryPos + META_INF_LEN, nlen - META_INF_LEN)) {
+                        manifestPos = pos;
+                        manifestNum++;
+                    } else {
+                        if (isSignatureRelated(entryPos, nlen)) {
+                            if (signatureNames == null)
+                                signatureNames = new ArrayList<>(4);
+                            signatureNames.add(pos);
+                        }
+
+                        // If this is a versioned entry, parse the version
+                        // and store it for later. This optimizes lookup
+                        // performance in multi-release jar files
+                        int version = getMetaVersion(entryPos + META_INF_LEN, nlen - META_INF_LEN);
+                        if (version > 0) {
+                            if (metaVersionsSet == null)
+                                metaVersionsSet = new TreeSet<>();
+                            metaVersionsSet.add(version);
+                        }
+                    }
+                }
+                // skip to the start of the next entry
+                pos = nextEntryPos(pos, entryPos, nlen);
+                entryPos = pos + CENHDR;
+            }
+
+            // Adjust the total entries
+            this.total = idx / 3;
+
+            if (signatureNames != null) {
+                int len = signatureNames.size();
+                signatureMetaNames = new int[len];
+                for (int j = 0; j < len; j++) {
+                    signatureMetaNames[j] = signatureNames.get(j);
+                }
+            }
+            if (metaVersionsSet != null) {
+                metaVersions = new int[metaVersionsSet.size()];
+                int c = 0;
+                for (Integer version : metaVersionsSet) {
+                    metaVersions[c++] = version;
+                }
+            } else {
+                metaVersions = EMPTY_META_VERSIONS;
+            }
+            if (pos + ENDHDR != cen.length) {
+                zerror("invalid CEN header (bad header size)");
+            }
+        }
+
+        private int nextEntryPos(int pos, int entryPos, int nlen) {
+            return entryPos + nlen + CENCOM(cen, pos) + CENEXT(cen, pos);
+        }
+
+        private static void zerror(String msg) throws ZipException {
+            throw new ZipException(msg);
+        }
+
+        /*
+         * Returns the {@code pos} of the zip cen entry corresponding to the
+         * specified entry name, or -1 if not found.
+         */
+        private int getEntryPos(String name, boolean addSlash) {
+            if (total == 0) {
+                return -1;
+            }
+
+            int hsh = ZipCoder.hash(name);
+            int idx = table[(hsh & 0x7fffffff) % tablelen];
+
+            // Search down the target hash chain for a entry whose
+            // 32 bit hash matches the hashed name.
+            while (idx != ZIP_ENDCHAIN) {
+                if (getEntryHash(idx) == hsh) {
+                    // The CEN name must match the specfied one
+                    int pos = getEntryPos(idx);
+
+                    try {
+                        ZipCoder zc = zipCoderForPos(pos);
+                        String entry = zc.toString(cen, pos + CENHDR, CENNAM(cen, pos));
+
+                        // If addSlash is true we'll test for name+/ in addition to
+                        // name, unless name is the empty string or already ends with a
+                        // slash
+                        int entryLen = entry.length();
+                        int nameLen = name.length();
+                        if ((entryLen == nameLen && entry.equals(name)) ||
+                                (addSlash &&
+                                nameLen + 1 == entryLen &&
+                                entry.startsWith(name) &&
+                                entry.charAt(entryLen - 1) == '/')) {
+                            return pos;
+                        }
+                    } catch (IllegalArgumentException iae) {
+                        // Ignore
+                    }
+                }
+                idx = getEntryNext(idx);
+            }
+            return -1;
+        }
+
+        private ZipCoder zipCoderForPos(int pos) {
+            if (zc.isUTF8()) {
+                return zc;
+            }
+            if ((CENFLG(cen, pos) & USE_UTF8) != 0) {
+                return ZipCoder.UTF8;
+            }
+            return zc;
+        }
+
+        /**
+         * Returns true if the bytes represent a non-directory name
+         * beginning with "META-INF/", disregarding ASCII case.
+         */
+        private static boolean isMetaName(byte[] name, int off, int len) {
+            // Use the "oldest ASCII trick in the book":
+            // ch | 0x20 == Character.toLowerCase(ch)
+            return len > META_INF_LEN       // "META-INF/".length()
+                && name[off + len - 1] != '/'  // non-directory
+                && (name[off++] | 0x20) == 'm'
+                && (name[off++] | 0x20) == 'e'
+                && (name[off++] | 0x20) == 't'
+                && (name[off++] | 0x20) == 'a'
+                && (name[off++]       ) == '-'
+                && (name[off++] | 0x20) == 'i'
+                && (name[off++] | 0x20) == 'n'
+                && (name[off++] | 0x20) == 'f'
+                && (name[off]         ) == '/';
+        }
+
+        /*
+         * Check if the bytes represents a name equals to MANIFEST.MF
+         */
+        private boolean isManifestName(int off, int len) {
+            byte[] name = cen;
+            return (len == 11 // "MANIFEST.MF".length()
+                    && (name[off++] | 0x20) == 'm'
+                    && (name[off++] | 0x20) == 'a'
+                    && (name[off++] | 0x20) == 'n'
+                    && (name[off++] | 0x20) == 'i'
+                    && (name[off++] | 0x20) == 'f'
+                    && (name[off++] | 0x20) == 'e'
+                    && (name[off++] | 0x20) == 's'
+                    && (name[off++] | 0x20) == 't'
+                    && (name[off++]       ) == '.'
+                    && (name[off++] | 0x20) == 'm'
+                    && (name[off]   | 0x20) == 'f');
+        }
+
+        private boolean isSignatureRelated(int off, int len) {
+            // Only called when isMetaName(name, off, len) is true, which means
+            // len is at least META_INF_LENGTH
+            // assert isMetaName(name, off, len)
+            boolean signatureRelated = false;
+            byte[] name = cen;
+            if (name[off + len - 3] == '.') {
+                // Check if entry ends with .EC and .SF
+                int b1 = name[off + len - 2] | 0x20;
+                int b2 = name[off + len - 1] | 0x20;
+                if ((b1 == 'e' && b2 == 'c') || (b1 == 's' && b2 == 'f')) {
+                    signatureRelated = true;
+                }
+            } else if (name[off + len - 4] == '.') {
+                // Check if entry ends with .DSA and .RSA
+                int b1 = name[off + len - 3] | 0x20;
+                int b2 = name[off + len - 2] | 0x20;
+                int b3 = name[off + len - 1] | 0x20;
+                if ((b1 == 'r' || b1 == 'd') && b2 == 's' && b3 == 'a') {
+                    signatureRelated = true;
+                }
+            }
+            // Above logic must match SignatureFileVerifier.isBlockOrSF
+            assert(signatureRelated == SignatureFileVerifier
+                // Android-changed: use StandardCharsets.
+                // .isBlockOrSF(new String(name, off, len, UTF_8.INSTANCE)
+                .isBlockOrSF(new String(name, off, len, StandardCharsets.UTF_8)
+                    .toUpperCase(Locale.ENGLISH)));
+            return signatureRelated;
+        }
+
+        /*
+         * If the bytes represents a non-directory name beginning
+         * with "versions/", continuing with a positive integer,
+         * followed by a '/', then return that integer value.
+         * Otherwise, return 0
+         */
+        private int getMetaVersion(int off, int len) {
+            byte[] name = cen;
+            int nend = off + len;
+            if (!(len > 10                         // "versions//".length()
+                    && name[off + len - 1] != '/'  // non-directory
+                    && (name[off++] | 0x20) == 'v'
+                    && (name[off++] | 0x20) == 'e'
+                    && (name[off++] | 0x20) == 'r'
+                    && (name[off++] | 0x20) == 's'
+                    && (name[off++] | 0x20) == 'i'
+                    && (name[off++] | 0x20) == 'o'
+                    && (name[off++] | 0x20) == 'n'
+                    && (name[off++] | 0x20) == 's'
+                    && (name[off++]       ) == '/')) {
+                return 0;
+            }
+            int version = 0;
+            while (off < nend) {
+                final byte c = name[off++];
+                if (c == '/') {
+                    return version;
+                }
+                if (c < '0' || c > '9') {
+                    return 0;
+                }
+                version = version * 10 + c - '0';
+                // Check for overflow and leading zeros
+                if (version <= 0) {
+                    return 0;
+                }
+            }
+            return 0;
+        }
+
+        /**
+         * Returns the number of CEN headers in a central directory.
+         * Will not throw, even if the zip file is corrupt.
+         *
+         * @param cen copy of the bytes in a zip file's central directory
+         * @param size number of bytes in central directory
+         */
+        private static int countCENHeaders(byte[] cen, int size) {
+            int count = 0;
+            for (int p = 0;
+                 p + CENHDR <= size;
+                 p += CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p))
+                count++;
+            return count;
+        }
+    }
+}
diff --git a/android-35/java/util/zip/ZipInputStream.java b/android-35/java/util/zip/ZipInputStream.java
new file mode 100644
index 0000000..617e7ff
--- /dev/null
+++ b/android-35/java/util/zip/ZipInputStream.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.PushbackInputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+import dalvik.system.ZipPathValidator;
+
+/**
+ * This class implements an input stream filter for reading files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class ZipInputStream extends InflaterInputStream implements ZipConstants {
+    private ZipEntry entry;
+    private int flag;
+    private CRC32 crc = new CRC32();
+    private long remaining;
+    private byte[] tmpbuf = new byte[512];
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    private boolean closed = false;
+    // this flag is set to true after EOF has reached for
+    // one entry
+    private boolean entryEOF = false;
+
+    private ZipCoder zc;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names.
+     *
+     * @param in the actual input stream
+     */
+    public ZipInputStream(InputStream in) {
+        // Android-changed: use StandardCharsets.
+        // this(in, UTF_8.INSTANCE);
+        this(in, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * @param in the actual input stream
+     *
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name (ignored if the
+     *        <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @since 1.7
+     */
+    public ZipInputStream(InputStream in, Charset charset) {
+        super(new PushbackInputStream(in, 512), new Inflater(true), 512);
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        if(in == null) {
+            throw new NullPointerException("in is null");
+        }
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+    }
+
+    // Android-changed: Additional ZipException throw scenario with ZipPathValidator.
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data.
+     *
+     * <p>If the app targets Android U or above, zip file entry names containing
+     * ".." or starting with "/" passed here will throw a {@link ZipException}.
+     * For more details, see {@link dalvik.system.ZipPathValidator}.
+     *
+     * @return the next ZIP file entry, or null if there are no more entries
+     * @throws ZipException if (1) a ZIP file error has occurred or
+     *            (2) <code>targetSdkVersion >= BUILD.VERSION_CODES.UPSIDE_DOWN_CAKE</code>
+     *            and (the <code>name</code> argument contains ".." or starts with "/").
+     * @throws IOException if an I/O error has occurred
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        ensureOpen();
+        if (entry != null) {
+            closeEntry();
+        }
+        crc.reset();
+        inf.reset();
+        if ((entry = readLOC()) == null) {
+            return null;
+        }
+        // Android-changed: Return more accurate value from available().
+        // Initialize the remaining field with the number of bytes that can be read from the entry
+        // for both uncompressed and compressed entries so that it can be used to provide a more
+        // accurate return value for available().
+        // if (entry.method == STORED) {
+        if (entry.method == STORED || entry.method == DEFLATED) {
+            remaining = entry.size;
+        }
+        entryEOF = false;
+        return entry;
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for reading the
+     * next entry.
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
+        entryEOF = true;
+    }
+
+    /**
+     * Returns 0 after EOF has reached for the current entry data,
+     * otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF has reached for current entry.
+     * @throws     IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        // Android-changed: Return more accurate value from available().
+        // Tracks the remaining bytes in order to return a more accurate value for the available
+        // bytes. Given an entry of size N both Android and upstream will return 1 until N bytes
+        // have been read at which point Android will return 0 and upstream will return 1.
+        // Upstream will only return 0 after an attempt to read a byte fails because the EOF has
+        // been reached. See http://b/111439440 for more details.
+        // if (entryEOF) {
+        if (entryEOF || (entry != null && remaining == 0)) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Reads from the current ZIP entry into an array of bytes.
+     * If {@code len} is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and {@code 0} is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array {@code b}
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @throws     NullPointerException if {@code b} is {@code null}.
+     * @throws     IndexOutOfBoundsException if {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code b.length - off}
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        if (entry == null) {
+            return -1;
+        }
+        switch (entry.method) {
+        case DEFLATED:
+            len = super.read(b, off, len);
+            if (len == -1) {
+                readEnd(entry);
+                entryEOF = true;
+                entry = null;
+            } else {
+                crc.update(b, off, len);
+                // Android-added: Return more accurate value from available().
+                // Update the remaining field so it is an accurate count of the number of bytes
+                // remaining in this stream, after deflation.
+                remaining -= len;
+            }
+            return len;
+        case STORED:
+            if (remaining <= 0) {
+                entryEOF = true;
+                entry = null;
+                return -1;
+            }
+            if (len > remaining) {
+                len = (int)remaining;
+            }
+            len = in.read(b, off, len);
+            if (len == -1) {
+                throw new ZipException("unexpected EOF");
+            }
+            crc.update(b, off, len);
+            remaining -= len;
+            if (remaining == 0 && entry.crc != crc.getValue()) {
+                throw new ZipException(
+                    "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
+                    " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+            }
+            return len;
+        default:
+            throw new ZipException("invalid compression method");
+        }
+    }
+
+    /**
+     * Skips specified number of bytes in the current ZIP entry.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O error has occurred
+     * @throws    IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > tmpbuf.length) {
+                len = tmpbuf.length;
+            }
+            len = read(tmpbuf, 0, len);
+            if (len == -1) {
+                entryEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    private byte[] b = new byte[256];
+
+    /*
+     * Reads local file (LOC) header for next entry.
+     */
+    private ZipEntry readLOC() throws IOException {
+        try {
+            readFully(tmpbuf, 0, LOCHDR);
+        } catch (EOFException e) {
+            return null;
+        }
+        if (get32(tmpbuf, 0) != LOCSIG) {
+            return null;
+        }
+        // get flag first, we need check USE_UTF8.
+        flag = get16(tmpbuf, LOCFLG);
+        // get the entry name and create the ZipEntry first
+        int len = get16(tmpbuf, LOCNAM);
+        int blen = b.length;
+        if (len > blen) {
+            do {
+                blen = blen * 2;
+            } while (len > blen);
+            b = new byte[blen];
+        }
+        readFully(b, 0, len);
+        // Force to use UTF-8 if the USE_UTF8 bit is ON
+        ZipEntry e = createZipEntry(((flag & USE_UTF8) != 0)
+                                    ? ZipCoder.toStringUTF8(b, len)
+                                    : zc.toString(b, len));
+        // now get the remaining fields for the entry
+        if ((flag & 1) == 1) {
+            throw new ZipException("encrypted ZIP entry not supported");
+        }
+        // BEGIN Android-added: Use ZipPathValidator to validate zip entry name.
+        ZipPathValidator.getInstance().onZipEntryAccess(e.name);
+        // END Android-added: Use ZipPathValidator to validate zip entry name.
+        e.method = get16(tmpbuf, LOCHOW);
+        e.xdostime = get32(tmpbuf, LOCTIM);
+        if ((flag & 8) == 8) {
+            // Android-changed: Remove the requirement that only DEFLATED entries
+            // can have data descriptors. This is not required by the ZIP spec and
+            // is inconsistent with the behaviour of ZipFile and versions of Android
+            // prior to Android N.
+            //
+            // /* "Data Descriptor" present */
+            // if (e.method != DEFLATED) {
+            //     throw new ZipException(
+            //             "only DEFLATED entries can have EXT descriptor");
+            // }
+        } else {
+            e.crc = get32(tmpbuf, LOCCRC);
+            e.csize = get32(tmpbuf, LOCSIZ);
+            e.size = get32(tmpbuf, LOCLEN);
+        }
+        len = get16(tmpbuf, LOCEXT);
+        if (len > 0) {
+            byte[] extra = new byte[len];
+            readFully(extra, 0, len);
+            e.setExtra0(extra,
+                        e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL, true);
+        }
+        return e;
+    }
+
+    /**
+     * Creates a new {@code ZipEntry} object for the specified
+     * entry name.
+     *
+     * @param name the ZIP file entry name
+     * @return the ZipEntry just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        return new ZipEntry(name);
+    }
+
+    /**
+     * Reads end of deflated entry as well as EXT descriptor if present.
+     *
+     * Local headers for DEFLATED entries may optionally be followed by a
+     * data descriptor, and that data descriptor may optionally contain a
+     * leading signature (EXTSIG).
+     *
+     * From the zip spec http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+     *
+     * """Although not originally assigned a signature, the value 0x08074b50
+     * has commonly been adopted as a signature value for the data descriptor
+     * record.  Implementers should be aware that ZIP files may be
+     * encountered with or without this signature marking data descriptors
+     * and should account for either case when reading ZIP files to ensure
+     * compatibility."""
+     */
+    private void readEnd(ZipEntry e) throws IOException {
+        int n = inf.getRemaining();
+        if (n > 0) {
+            ((PushbackInputStream)in).unread(buf, len - n, n);
+        }
+        if ((flag & 8) == 8) {
+            /* "Data Descriptor" present */
+            if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
+                inf.getBytesRead() > ZIP64_MAGICVAL) {
+                // ZIP64 format
+                readFully(tmpbuf, 0, ZIP64_EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                        tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, ZIP64_EXTCRC);
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN);
+                }
+            } else {
+                readFully(tmpbuf, 0, EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
+                    e.size = get32(tmpbuf, EXTLEN - EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                                               tmpbuf, EXTHDR - EXTCRC, EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, EXTCRC);
+                    e.csize = get32(tmpbuf, EXTSIZ);
+                    e.size = get32(tmpbuf, EXTLEN);
+                }
+            }
+        }
+        if (e.size != inf.getBytesWritten()) {
+            throw new ZipException(
+                "invalid entry size (expected " + e.size +
+                " but got " + inf.getBytesWritten() + " bytes)");
+        }
+        if (e.csize != inf.getBytesRead()) {
+            throw new ZipException(
+                "invalid entry compressed size (expected " + e.csize +
+                " but got " + inf.getBytesRead() + " bytes)");
+        }
+        if (e.crc != crc.getValue()) {
+            throw new ZipException(
+                "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
+                " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+        }
+    }
+
+    /*
+     * Reads bytes, blocking until all bytes are read.
+     */
+    private void readFully(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            int n = in.read(b, off, len);
+            if (n == -1) {
+                throw new EOFException();
+            }
+            off += n;
+            len -= n;
+        }
+    }
+
+}
diff --git a/android-35/java/util/zip/ZipOutputStream.java b/android-35/java/util/zip/ZipOutputStream.java
new file mode 100644
index 0000000..6b6a68c
--- /dev/null
+++ b/android-35/java/util/zip/ZipOutputStream.java
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Vector;
+import java.util.HashSet;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * This class implements an output stream filter for writing files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ * @since 1.1
+ */
+public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
+
+    /**
+     * Whether to use ZIP64 for zip files with more than 64k entries.
+     * Until ZIP64 support in zip implementations is ubiquitous, this
+     * system property allows the creation of zip files which can be
+     * read by legacy zip implementations which tolerate "incorrect"
+     * total entry count fields, such as the ones in jdk6, and even
+     * some in jdk7.
+     */
+    // Android-changed: Always allow use of Zip64.
+    private static final boolean inhibitZip64 = false;
+        // Boolean.parseBoolean(
+        //    GetPropertyAction.privilegedGetProperty("jdk.util.zip.inhibitZip64"));
+
+    private static class XEntry {
+        final ZipEntry entry;
+        final long offset;
+        public XEntry(ZipEntry entry, long offset) {
+            this.entry = entry;
+            this.offset = offset;
+        }
+    }
+
+    private XEntry current;
+    private Vector<XEntry> xentries = new Vector<>();
+    private HashSet<String> names = new HashSet<>();
+    private CRC32 crc = new CRC32();
+    private long written = 0;
+    private long locoff = 0;
+    private byte[] comment;
+    private int method = DEFLATED;
+    private boolean finished;
+
+    private boolean closed = false;
+
+    private final ZipCoder zc;
+
+    private static int version(ZipEntry e) throws ZipException {
+        return switch (e.method) {
+        case DEFLATED -> 20;
+        case STORED   -> 10;
+        default       -> throw new ZipException("unsupported compression method");
+        };
+    }
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Compression method for uncompressed (STORED) entries.
+     */
+    public static final int STORED = ZipEntry.STORED;
+
+    /**
+     * Compression method for compressed (DEFLATED) entries.
+     */
+    public static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
+     * to encode the entry names and comments.
+     *
+     * @param out the actual output stream
+     */
+    public ZipOutputStream(OutputStream out) {
+        this(out, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * @param out the actual output stream
+     *
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     *                to be used to encode the entry names and comments
+     *
+     * @since 1.7
+     */
+    public ZipOutputStream(OutputStream out, Charset charset) {
+        super(out, out != null ? new Deflater(Deflater.DEFAULT_COMPRESSION, true) : null);
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Sets the ZIP file comment.
+     * @param     comment the comment string
+     * @throws    IllegalArgumentException if the length of the specified
+     *            ZIP file comment is greater than 0xFFFF bytes
+     */
+    public void setComment(String comment) {
+        byte[] bytes = null;
+        if (comment != null) {
+            bytes = zc.getBytes(comment);
+            if (bytes.length > 0xffff) {
+                throw new IllegalArgumentException("ZIP file comment too long");
+            }
+        }
+        this.comment = bytes;
+    }
+
+    /**
+     * Sets the default compression method for subsequent entries. This
+     * default will be used whenever the compression method is not specified
+     * for an individual ZIP file entry, and is initially set to DEFLATED.
+     * @param     method the default compression method
+     * @throws    IllegalArgumentException if the specified compression method
+     *            is invalid
+     */
+    public void setMethod(int method) {
+        if (method != DEFLATED && method != STORED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Sets the compression level for subsequent entries which are DEFLATED.
+     * The default setting is DEFAULT_COMPRESSION.
+     * @param     level the compression level (0-9)
+     * @throws    IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        def.setLevel(level);
+    }
+
+    /**
+     * Begins writing a new ZIP file entry and positions the stream to the
+     * start of the entry data. Closes the current entry if still active.
+     * <p>
+     * The default compression method will be used if no compression method
+     * was specified for the entry. When writing a compressed (DEFLATED)
+     * entry, and the compressed size has not been explicitly set with the
+     * {@link ZipEntry#setCompressedSize(long)} method, then the compressed
+     * size will be set to the actual compressed size after deflation.
+     * <p>
+     * The current time will be used if the entry has no set modification time.
+     *
+     * @param     e the ZIP entry to be written
+     * @throws    ZipException if a ZIP format error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry e) throws IOException {
+        ensureOpen();
+        if (current != null) {
+            closeEntry();       // close previous entry
+        }
+        if (e.xdostime == -1) {
+            // by default, do NOT use extended timestamps in extra
+            // data, for now.
+            e.setTime(System.currentTimeMillis());
+        }
+        if (e.method == -1) {
+            e.method = method;  // use default method
+        }
+        // store size, compressed size, and crc-32 in LOC header
+        e.flag = 0;
+        switch (e.method) {
+        case DEFLATED:
+            // If not set, store size, compressed size, and crc-32 in data
+            // descriptor immediately following the compressed entry data.
+            // Ignore the compressed size of a ZipEntry if it was implcitely set
+            // while reading that ZipEntry from a  ZipFile or ZipInputStream because
+            // we can't know the compression level of the source zip file/stream.
+            if (e.size  == -1 || e.csize == -1 || e.crc   == -1 || !e.csizeSet) {
+                e.flag = 8;
+            }
+            break;
+        case STORED:
+            // compressed size, uncompressed size, and crc-32 must all be
+            // set for entries using STORED compression method
+            if (e.size == -1) {
+                e.size = e.csize;
+            } else if (e.csize == -1) {
+                e.csize = e.size;
+            } else if (e.size != e.csize) {
+                throw new ZipException(
+                    "STORED entry where compressed != uncompressed size");
+            }
+            if (e.size == -1 || e.crc == -1) {
+                throw new ZipException(
+                    "STORED entry missing size, compressed size, or crc-32");
+            }
+            break;
+        default:
+            throw new ZipException("unsupported compression method");
+        }
+        if (! names.add(e.name)) {
+            throw new ZipException("duplicate entry: " + e.name);
+        }
+        if (zc.isUTF8())
+            e.flag |= USE_UTF8;
+        current = new XEntry(e, written);
+        xentries.add(current);
+        writeLOC(current);
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for writing
+     * the next entry.
+     * @throws    ZipException if a ZIP format error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        if (current != null) {
+            try {
+                ZipEntry e = current.entry;
+                switch (e.method) {
+                    case DEFLATED -> {
+                        def.finish();
+                        while (!def.finished()) {
+                            deflate();
+                        }
+                        if ((e.flag & 8) == 0) {
+                            // verify size, compressed size, and crc-32 settings
+                            if (e.size != def.getBytesRead()) {
+                                throw new ZipException(
+                                    "invalid entry size (expected " + e.size +
+                                    " but got " + def.getBytesRead() + " bytes)");
+                            }
+                            if (e.csize != def.getBytesWritten()) {
+                                throw new ZipException(
+                                    "invalid entry compressed size (expected " +
+                                    e.csize + " but got " + def.getBytesWritten() + " bytes)");
+                            }
+                            if (e.crc != crc.getValue()) {
+                                throw new ZipException(
+                                    "invalid entry CRC-32 (expected 0x" +
+                                    Long.toHexString(e.crc) + " but got 0x" +
+                                    Long.toHexString(crc.getValue()) + ")");
+                            }
+                        } else {
+                            e.size = def.getBytesRead();
+                            e.csize = def.getBytesWritten();
+                            e.crc = crc.getValue();
+                            writeEXT(e);
+                        }
+                        def.reset();
+                        written += e.csize;
+                    }
+                    case STORED -> {
+                        // we already know that both e.size and e.csize are the same
+                        if (e.size != written - locoff) {
+                            throw new ZipException(
+                                "invalid entry size (expected " + e.size +
+                                " but got " + (written - locoff) + " bytes)");
+                        }
+                        if (e.crc != crc.getValue()) {
+                            throw new ZipException(
+                                "invalid entry crc-32 (expected 0x" +
+                                Long.toHexString(e.crc) + " but got 0x" +
+                                Long.toHexString(crc.getValue()) + ")");
+                        }
+                    }
+                    default -> throw new ZipException("invalid compression method");
+                }
+                crc.reset();
+                current = null;
+            } catch (IOException e) {
+                if (def.shouldFinish() && usesDefaultDeflater && !(e instanceof ZipException))
+                    def.end();
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * Writes an array of bytes to the current ZIP entry data. This method
+     * will block until all the bytes are written.
+     * @param     b the data to be written
+     * @param     off the start offset in the data
+     * @param     len the number of bytes that are written
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public synchronized void write(byte[] b, int off, int len)
+        throws IOException
+    {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        if (current == null) {
+            throw new ZipException("no current ZIP entry");
+        }
+        ZipEntry entry = current.entry;
+        switch (entry.method) {
+            case DEFLATED -> super.write(b, off, len);
+            case STORED -> {
+                written += len;
+                if (written - locoff > entry.size) {
+                    throw new ZipException(
+                        "attempt to write past end of STORED entry");
+                }
+                out.write(b, off, len);
+            }
+            default -> throw new ZipException("invalid compression method");
+        }
+        crc.update(b, off, len);
+    }
+
+    /**
+     * Finishes writing the contents of the ZIP output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O exception has occurred
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+        if (finished) {
+            return;
+        }
+        if (current != null) {
+            closeEntry();
+        }
+        // write central directory
+        long off = written;
+        for (XEntry xentry : xentries)
+            writeCEN(xentry);
+        writeEND(off, written - off);
+        finished = true;
+    }
+
+    /**
+     * Closes the ZIP output stream as well as the stream being filtered.
+     * @throws    ZipException if a ZIP file error has occurred
+     * @throws    IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    /*
+     * Writes local file (LOC) header for specified entry.
+     */
+    private void writeLOC(XEntry xentry) throws IOException {
+        ZipEntry e = xentry.entry;
+        int flag = e.flag;
+        boolean hasZip64 = false;
+        int elen = getExtraLen(e.extra);
+
+        writeInt(LOCSIG);               // LOC header signature
+        if ((flag & 8) == 8) {
+            writeShort(version(e));     // version needed to extract
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            // store size, uncompressed size, and crc-32 in data descriptor
+            // immediately following compressed entry data
+            writeInt(0);
+            writeInt(0);
+            writeInt(0);
+        } else {
+            if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+                hasZip64 = true;
+                writeShort(45);         // ver 4.5 for zip64
+            } else {
+                writeShort(version(e)); // version needed to extract
+            }
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            writeInt(e.crc);            // crc-32
+            if (hasZip64) {
+                writeInt(ZIP64_MAGICVAL);
+                writeInt(ZIP64_MAGICVAL);
+                elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
+            } else {
+                writeInt(e.csize);  // compressed size
+                writeInt(e.size);   // uncompressed size
+            }
+        }
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elenEXTT = 0;         // info-zip extended timestamp
+        int flagEXTT = 0;
+        long umtime = -1;
+        long uatime = -1;
+        long uctime = -1;
+        if (e.mtime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LMT;
+            umtime = fileTimeToUnixTime(e.mtime);
+        }
+        if (e.atime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LAT;
+            uatime = fileTimeToUnixTime(e.atime);
+        }
+        if (e.ctime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAT_CT;
+            uctime = fileTimeToUnixTime(e.ctime);
+        }
+        if (flagEXTT != 0) {
+            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                elen += 36;                // NTFS time, total 36 bytes
+            } else {
+                elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
+            }
+        }
+        writeShort(elen);
+        writeBytes(nameBytes, 0, nameBytes.length);
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);
+            writeShort(16);
+            writeLong(e.size);
+            writeLong(e.csize);
+        }
+        if (flagEXTT != 0) {
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                writeShort(EXTID_NTFS);    // id
+                writeShort(32);            // data size
+                writeInt(0);               // reserved
+                writeShort(0x0001);        // NTFS attr tag
+                writeShort(24);
+                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.mtime));
+                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.atime));
+                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.ctime));
+            } else {
+                writeShort(EXTID_EXTT);
+                writeShort(elenEXTT + 1);  // flag + data
+                writeByte(flagEXTT);
+                if (e.mtime != null)
+                    writeInt(umtime);
+                if (e.atime != null)
+                    writeInt(uatime);
+                if (e.ctime != null)
+                    writeInt(uctime);
+            }
+        }
+        writeExtra(e.extra);
+        locoff = written;
+    }
+
+    /*
+     * Writes extra data descriptor (EXT) for specified entry.
+     */
+    private void writeEXT(ZipEntry e) throws IOException {
+        writeInt(EXTSIG);           // EXT header signature
+        writeInt(e.crc);            // crc-32
+        if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+            writeLong(e.csize);
+            writeLong(e.size);
+        } else {
+            writeInt(e.csize);          // compressed size
+            writeInt(e.size);           // uncompressed size
+        }
+    }
+
+    /**
+     * Adds information about compatibility of file attribute information
+     * to a version value.
+     */
+    private int versionMadeBy(ZipEntry e, int version) {
+        return (e.extraAttributes < 0) ? version :
+                VERSION_MADE_BY_BASE_UNIX | (version & 0xff);
+    }
+
+    /*
+     * Write central directory (CEN) header for specified entry.
+     * REMIND: add support for file attributes
+     */
+    private void writeCEN(XEntry xentry) throws IOException {
+        ZipEntry e  = xentry.entry;
+        int flag = e.flag;
+        int version = version(e);
+        long csize = e.csize;
+        long size = e.size;
+        long offset = xentry.offset;
+        int elenZIP64 = 0;
+        boolean hasZip64 = false;
+
+        if (e.csize >= ZIP64_MAGICVAL) {
+            csize = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // csize(8)
+            hasZip64 = true;
+        }
+        if (e.size >= ZIP64_MAGICVAL) {
+            size = ZIP64_MAGICVAL;    // size(8)
+            elenZIP64 += 8;
+            hasZip64 = true;
+        }
+        if (xentry.offset >= ZIP64_MAGICVAL) {
+            offset = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // offset(8)
+            hasZip64 = true;
+        }
+        writeInt(CENSIG);           // CEN header signature
+        if (hasZip64) {
+            writeShort(versionMadeBy(e,45));         // ver 4.5 for zip64
+            writeShort(45);
+        } else {
+            writeShort(versionMadeBy(e, version));    // version made by
+            writeShort(version);    // version needed to extract
+        }
+        writeShort(flag);           // general purpose bit flag
+        writeShort(e.method);       // compression method
+        writeInt(e.xdostime);       // last modification time
+        writeInt(e.crc);            // crc-32
+        writeInt(csize);            // compressed size
+        writeInt(size);             // uncompressed size
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elen = getExtraLen(e.extra);
+        if (hasZip64) {
+            elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
+        }
+        // cen info-zip extended timestamp only outputs mtime
+        // but set the flag for a/ctime, if present in loc
+        int flagEXTT = 0;
+        long umtime = -1;
+        long uatime = -1;
+        long uctime = -1;
+        if (e.mtime != null) {
+            flagEXTT |= EXTT_FLAG_LMT;
+            umtime = fileTimeToUnixTime(e.mtime);
+        }
+        if (e.atime != null) {
+            flagEXTT |= EXTT_FLAG_LAT;
+            uatime = fileTimeToUnixTime(e.atime);
+        }
+        if (e.ctime != null) {
+            flagEXTT |= EXTT_FLAT_CT;
+            uctime = fileTimeToUnixTime(e.ctime);
+        }
+        if (flagEXTT != 0) {
+            // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                elen += 36;         // NTFS time total 36 bytes
+            } else {
+                elen += 5;          // headid(2) + sz(2) + flag(1)
+                if (e.mtime != null)
+                    elen += 4;      // + mtime (4)
+            }
+        }
+        writeShort(elen);
+        byte[] commentBytes;
+        if (e.comment != null) {
+            commentBytes = zc.getBytes(e.comment);
+            writeShort(Math.min(commentBytes.length, 0xffff));
+        } else {
+            commentBytes = null;
+            writeShort(0);
+        }
+        writeShort(0);              // starting disk number
+        writeShort(0);              // internal file attributes (unused)
+        // extra file attributes, used for storing posix permissions etc.
+        writeInt(e.extraAttributes > 0 ? e.extraAttributes << 16 : 0);
+        writeInt(offset);           // relative offset of local header
+        writeBytes(nameBytes, 0, nameBytes.length);
+
+        // take care of EXTID_ZIP64 and EXTID_EXTT
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);// Zip64 extra
+            writeShort(elenZIP64);
+            if (size == ZIP64_MAGICVAL)
+                writeLong(e.size);
+            if (csize == ZIP64_MAGICVAL)
+                writeLong(e.csize);
+            if (offset == ZIP64_MAGICVAL)
+                writeLong(xentry.offset);
+        }
+        if (flagEXTT != 0) {
+            if (umtime > UPPER_UNIXTIME_BOUND ||
+                uatime > UPPER_UNIXTIME_BOUND ||
+                uctime > UPPER_UNIXTIME_BOUND) {
+                writeShort(EXTID_NTFS);    // id
+                writeShort(32);            // data size
+                writeInt(0);               // reserved
+                writeShort(0x0001);        // NTFS attr tag
+                writeShort(24);
+                writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.mtime));
+                writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.atime));
+                writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+                                          : fileTimeToWinTime(e.ctime));
+            } else {
+                writeShort(EXTID_EXTT);
+                if (e.mtime != null) {
+                    writeShort(5);      // flag + mtime
+                    writeByte(flagEXTT);
+                    writeInt(umtime);
+                } else {
+                    writeShort(1);      // flag only
+                    writeByte(flagEXTT);
+                }
+            }
+        }
+        writeExtra(e.extra);
+        if (commentBytes != null) {
+            writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
+        }
+    }
+
+    /*
+     * Writes end of central directory (END) header.
+     */
+    private void writeEND(long off, long len) throws IOException {
+        boolean hasZip64 = false;
+        long xlen = len;
+        long xoff = off;
+        if (xlen >= ZIP64_MAGICVAL) {
+            xlen = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        if (xoff >= ZIP64_MAGICVAL) {
+            xoff = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        int count = xentries.size();
+        if (count >= ZIP64_MAGICCOUNT) {
+            hasZip64 |= !inhibitZip64;
+            if (hasZip64) {
+                count = ZIP64_MAGICCOUNT;
+            }
+        }
+        if (hasZip64) {
+            long off64 = written;
+            //zip64 end of central directory record
+            writeInt(ZIP64_ENDSIG);        // zip64 END record signature
+            writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
+            writeShort(45);                // version made by
+            writeShort(45);                // version needed to extract
+            writeInt(0);                   // number of this disk
+            writeInt(0);                   // central directory start disk
+            writeLong(xentries.size());    // number of directory entires on disk
+            writeLong(xentries.size());    // number of directory entires
+            writeLong(len);                // length of central directory
+            writeLong(off);                // offset of central directory
+
+            //zip64 end of central directory locator
+            writeInt(ZIP64_LOCSIG);        // zip64 END locator signature
+            writeInt(0);                   // zip64 END start disk
+            writeLong(off64);              // offset of zip64 END
+            writeInt(1);                   // total number of disks (?)
+        }
+        writeInt(ENDSIG);                 // END record signature
+        writeShort(0);                    // number of this disk
+        writeShort(0);                    // central directory start disk
+        writeShort(count);                // number of directory entries on disk
+        writeShort(count);                // total number of directory entries
+        writeInt(xlen);                   // length of central directory
+        writeInt(xoff);                   // offset of central directory
+        if (comment != null) {            // zip file comment
+            writeShort(comment.length);
+            writeBytes(comment, 0, comment.length);
+        } else {
+            writeShort(0);
+        }
+    }
+
+    /*
+     * Returns the length of extra data without EXTT and ZIP64.
+     */
+    private int getExtraLen(byte[] extra) {
+        if (extra == null)
+            return 0;
+        int skipped = 0;
+        int len = extra.length;
+        int off = 0;
+        while (off + 4 <= len) {
+            int tag = get16(extra, off);
+            int sz = get16(extra, off + 2);
+            if (sz < 0 || (off + 4 + sz) > len) {
+                break;
+            }
+            if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
+                skipped += (sz + 4);
+            }
+            off += (sz + 4);
+        }
+        return len - skipped;
+    }
+
+    /*
+     * Writes extra data without EXTT and ZIP64.
+     *
+     * Extra timestamp and ZIP64 data is handled/output separately
+     * in writeLOC and writeCEN.
+     */
+    private void writeExtra(byte[] extra) throws IOException {
+        if (extra != null) {
+            int len = extra.length;
+            int off = 0;
+            while (off + 4 <= len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                if (sz < 0 || (off + 4 + sz) > len) {
+                    writeBytes(extra, off, len - off);
+                    return;
+                }
+                if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
+                    writeBytes(extra, off, sz + 4);
+                }
+                off += (sz + 4);
+            }
+            if (off < len) {
+                writeBytes(extra, off, len - off);
+            }
+        }
+    }
+
+    /*
+     * Writes a 8-bit byte to the output stream.
+     */
+    private void writeByte(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write(v & 0xff);
+        written += 1;
+    }
+
+    /*
+     * Writes a 16-bit short to the output stream in little-endian byte order.
+     */
+    private void writeShort(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write((v >>> 0) & 0xff);
+        out.write((v >>> 8) & 0xff);
+        written += 2;
+    }
+
+    /*
+     * Writes a 32-bit int to the output stream in little-endian byte order.
+     */
+    private void writeInt(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        written += 4;
+    }
+
+    /*
+     * Writes a 64-bit int to the output stream in little-endian byte order.
+     */
+    private void writeLong(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        out.write((int)((v >>> 32) & 0xff));
+        out.write((int)((v >>> 40) & 0xff));
+        out.write((int)((v >>> 48) & 0xff));
+        out.write((int)((v >>> 56) & 0xff));
+        written += 8;
+    }
+
+    /*
+     * Writes an array of bytes to the output stream.
+     */
+    private void writeBytes(byte[] b, int off, int len) throws IOException {
+        super.out.write(b, off, len);
+        written += len;
+    }
+}
diff --git a/android-35/java/util/zip/ZipUtils.java b/android-35/java/util/zip/ZipUtils.java
new file mode 100644
index 0000000..dd5106e
--- /dev/null
+++ b/android-35/java/util/zip/ZipUtils.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import java.nio.file.attribute.FileTime;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import static java.util.zip.ZipConstants.ENDHDR;
+
+import jdk.internal.misc.Unsafe;
+
+class ZipUtils {
+
+    // used to adjust values between Windows and java epoch
+    private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
+
+    // used to indicate the corresponding windows time is not available
+    public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
+
+    // static final ByteBuffer defaultBuf = ByteBuffer.allocateDirect(0);
+    static final ByteBuffer defaultBuf = ByteBuffer.allocate(0);
+
+    /**
+     * Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
+     */
+    public static final FileTime winTimeToFileTime(long wtime) {
+        return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
+                             TimeUnit.MICROSECONDS);
+    }
+
+    /**
+     * Converts FileTime to Windows time.
+     */
+    public static final long fileTimeToWinTime(FileTime ftime) {
+        return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
+    }
+
+    /**
+     * The upper bound of the 32-bit unix time, the "year 2038 problem".
+     */
+    public static final long UPPER_UNIXTIME_BOUND = 0x7fffffff;
+
+    /**
+     * Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
+     */
+    public static final FileTime unixTimeToFileTime(long utime) {
+        return FileTime.from(utime, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts FileTime to "standard Unix time".
+     */
+    public static final long fileTimeToUnixTime(FileTime ftime) {
+        return ftime.to(TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts DOS time to Java time (number of milliseconds since epoch).
+     */
+    public static long dosToJavaTime(long dtime) {
+        int year = (int) (((dtime >> 25) & 0x7f) + 1980);
+        int month = (int) ((dtime >> 21) & 0x0f);
+        int day = (int) ((dtime >> 16) & 0x1f);
+        int hour = (int) ((dtime >> 11) & 0x1f);
+        int minute = (int) ((dtime >> 5) & 0x3f);
+        int second = (int) ((dtime << 1) & 0x3e);
+
+        if (month > 0 && month < 13 && day > 0 && hour < 24 && minute < 60 && second < 60) {
+            try {
+                LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
+                return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
+                        ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
+            } catch (DateTimeException dte) {
+                // ignore
+            }
+        }
+        return overflowDosToJavaTime(year, month, day, hour, minute, second);
+    }
+
+    /*
+     * Deal with corner cases where an arguably mal-formed DOS time is used
+     */
+    @SuppressWarnings("deprecation") // Use of Date constructor
+    private static long overflowDosToJavaTime(int year, int month, int day,
+                                              int hour, int minute, int second) {
+        return new Date(year - 1900, month - 1, day, hour, minute, second).getTime();
+    }
+
+
+    /**
+     * Converts extended DOS time to Java time, where up to 1999 milliseconds
+     * might be encoded into the upper half of the returned long.
+     *
+     * @param xdostime the extended DOS time value
+     * @return milliseconds since epoch
+     */
+    public static long extendedDosToJavaTime(long xdostime) {
+        long time = dosToJavaTime(xdostime);
+        return time + (xdostime >> 32);
+    }
+
+    /**
+     * Converts Java time to DOS time.
+     */
+    private static long javaToDosTime(LocalDateTime ldt) {
+        int year = ldt.getYear() - 1980;
+        return (year << 25 |
+            ldt.getMonthValue() << 21 |
+            ldt.getDayOfMonth() << 16 |
+            ldt.getHour() << 11 |
+            ldt.getMinute() << 5 |
+            ldt.getSecond() >> 1) & 0xffffffffL;
+    }
+
+    /**
+     * Converts Java time to DOS time, encoding any milliseconds lost
+     * in the conversion into the upper half of the returned long.
+     *
+     * @param time milliseconds since epoch
+     * @return DOS time with 2s remainder encoded into upper half
+     */
+    static long javaToExtendedDosTime(long time) {
+        LocalDateTime ldt = javaEpochToLocalDateTime(time);
+        if (ldt.getYear() >= 1980) {
+            return javaToDosTime(ldt) + ((time % 2000) << 32);
+        }
+        return ZipEntry.DOSTIME_BEFORE_1980;
+    }
+
+    static LocalDateTime javaEpochToLocalDateTime(long time) {
+        Instant instant = Instant.ofEpochMilli(time);
+        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+    }
+
+    /**
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final int get16(byte b[], int off) {
+        return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
+    }
+
+    /**
+     * Fetches unsigned 32-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get32(byte b[], int off) {
+        return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+    }
+
+    /**
+     * Fetches signed 64-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get64(byte b[], int off) {
+        return get32(b, off) | (get32(b, off+4) << 32);
+    }
+
+    /**
+     * Fetches signed 32-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     *
+     */
+    public static final int get32S(byte b[], int off) {
+        return (get16(b, off) | (get16(b, off+2) << 16));
+    }
+
+    // fields access methods
+    static final int CH(byte[] b, int n) {
+        return b[n] & 0xff ;
+    }
+
+    static final int SH(byte[] b, int n) {
+        return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
+    }
+
+    static final long LG(byte[] b, int n) {
+        return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
+    }
+
+    static final long LL(byte[] b, int n) {
+        return (LG(b, n)) | (LG(b, n + 4) << 32);
+    }
+
+    static final long GETSIG(byte[] b) {
+        return LG(b, 0);
+    }
+
+    /*
+     * File attribute compatibility types of CEN field "version made by"
+     */
+    static final int FILE_ATTRIBUTES_UNIX = 3; // Unix
+
+    /*
+     * Base values for CEN field "version made by"
+     */
+    static final int VERSION_MADE_BY_BASE_UNIX = FILE_ATTRIBUTES_UNIX << 8; // Unix
+
+
+    // local file (LOC) header fields
+    static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
+    static final int  LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
+    static final int  LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
+    static final int  LOCHOW(byte[] b) { return SH(b, 8); } // compression method
+    static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
+    static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
+    static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
+    static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
+    static final int  LOCNAM(byte[] b) { return SH(b, 26);} // filename length
+    static final int  LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
+
+    // extra local (EXT) header fields
+    static final long EXTCRC(byte[] b) { return LG(b, 4);}  // crc of uncompressed data
+    static final long EXTSIZ(byte[] b) { return LG(b, 8);}  // compressed size
+    static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
+
+    // end of central directory header (END) fields
+    static final int  ENDSUB(byte[] b) { return SH(b, 8); }  // number of entries on this disk
+    static final int  ENDTOT(byte[] b) { return SH(b, 10);}  // total number of entries
+    static final long ENDSIZ(byte[] b) { return LG(b, 12);}  // central directory size
+    static final long ENDOFF(byte[] b) { return LG(b, 16);}  // central directory offset
+    static final int  ENDCOM(byte[] b) { return SH(b, 20);}  // size of zip file comment
+    static final int  ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
+
+    // zip64 end of central directory recoder fields
+    static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);}  // total number of entries on disk
+    static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);}  // total number of entries
+    static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);}  // central directory size
+    static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);}  // central directory offset
+    static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);}   // zip64 end offset
+
+    // central directory header (CEN) fields
+    static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
+    static final int  CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
+    static final int  CENVEM_FA(byte[] b, int pos) { return CH(b, pos + 5); } // file attribute compatibility
+    static final int  CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
+    static final int  CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
+    static final int  CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
+    static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
+    static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
+    static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
+    static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
+    static final int  CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
+    static final int  CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
+    static final int  CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
+    static final int  CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
+    static final int  CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
+    static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
+    static final int  CENATX_PERMS(byte[] b, int pos) { return SH(b, pos + 40);} // posix permission data
+    static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
+
+    // The END header is followed by a variable length comment of size < 64k.
+    static final long END_MAXLEN = 0xFFFF + ENDHDR;
+    static final int READBLOCKSZ = 128;
+
+    // Android-removed: not available on Android.
+    /*
+     * Loads zip native library, if not already laoded
+     *
+    static void loadLibrary() {
+        jdk.internal.loader.BootLoader.loadLibrary("zip");
+    }
+    */
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb");
+    private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset");
+
+    static byte[] getBufferArray(ByteBuffer byteBuffer) {
+        return (byte[]) unsafe.getReference(byteBuffer, byteBufferArrayOffset);
+    }
+
+    static int getBufferOffset(ByteBuffer byteBuffer) {
+        return unsafe.getInt(byteBuffer, byteBufferOffsetOffset);
+    }
+}
diff --git a/android-35/java/util/zip/package-info.java b/android-35/java/util/zip/package-info.java
new file mode 100644
index 0000000..f4a38d6
--- /dev/null
+++ b/android-35/java/util/zip/package-info.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes for reading and writing the standard ZIP and GZIP file
+ * formats. Also includes classes for compressing and decompressing data using
+ * the DEFLATE compression algorithm, which is used by the ZIP and GZIP file
+ * formats. Additionally, there are utility classes for computing the CRC-32,
+ * CRC-32C and Adler-32 checksums of arbitrary input streams.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *     <li><a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">
+ *         Info-ZIP Application Note 970311</a> - a detailed description of
+ *         the Info-ZIP format upon which the {@code java.util.zip} classes
+ *         are based.
+ *     <li><a id="zip64">An implementation may optionally support the
+ *         ZIP64(tm) format extensions defined by the</a>
+ *         <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
+ *         PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format
+ *         extensions are used to overcome the size limitations of the
+ *         original ZIP format.
+ *     <li><a id="lang_encoding">APPENDIX D of</a>
+ *         <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
+ *         PKWARE ZIP File Format Specification</a> - Language Encoding Flag
+ *         to encode ZIP entry filename and comment fields using UTF-8.
+ *     <li><a href="http://www.ietf.org/rfc/rfc1950.txt">
+ *         ZLIB Compressed Data Format Specification version 3.3</a>
+ *         &nbsp;
+ *         <a href="http://www.ietf.org/rfc/rfc1950.txt.pdf">(pdf)</a>
+ *         (RFC 1950)
+ *     <li><a href="http://www.ietf.org/rfc/rfc1951.txt">
+ *         DEFLATE Compressed Data Format Specification version 1.3</a>
+ *         &nbsp;
+ *         <a href="http://www.ietf.org/rfc/rfc1951.txt.pdf">(pdf)</a>
+ *         (RFC 1951)
+ *     <li><a href="http://www.ietf.org/rfc/rfc1952.txt">
+ *         GZIP file format specification version 4.3</a>
+ *         &nbsp;
+ *         <a href="http://www.ietf.org/rfc/rfc1952.txt.pdf">(pdf)</a>
+ *         (RFC 1952)
+ *     <li>CRC-32 checksum is described in RFC 1952 (above)
+ *     <li>CRC-32C checksum is described in
+ *         <a href="http://www.ietf.org/rfc/rfc3720.txt">Internet Small
+ *         Computer Systems Interface (iSCSI)</a>
+ *         &nbsp;
+ *         <a href="http://www.ietf.org/rfc/rfc3720.txt.pdf">(pdf)</a>
+ *         (RFC 3720)
+ *     <li>Adler-32 checksum is described in RFC 1950 (above)
+ * </ul>
+ *
+ * @since 1.1
+ */
+package java.util.zip;